summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
Diffstat (limited to 'module')
-rw-r--r--module/plugins/Account.py45
-rw-r--r--module/plugins/AccountManager.py59
-rw-r--r--module/plugins/Container.py25
-rw-r--r--module/plugins/Crypter.py28
-rw-r--r--module/plugins/Hook.py30
-rw-r--r--module/plugins/Hoster.py7
-rw-r--r--module/plugins/Plugin.py30
-rw-r--r--module/plugins/PluginManager.py10
-rw-r--r--module/plugins/ReCaptcha.py24
-rw-r--r--module/plugins/accounts/AlldebridCom.py41
-rw-r--r--module/plugins/accounts/BayfilesCom.py51
-rw-r--r--module/plugins/accounts/BillionuploadsCom.py16
-rw-r--r--module/plugins/accounts/BitshareCom.py33
-rw-r--r--module/plugins/accounts/CatShareNet.py56
-rw-r--r--module/plugins/accounts/CloudzillaTo.py36
-rw-r--r--module/plugins/accounts/CramitIn.py17
-rw-r--r--module/plugins/accounts/CyberlockerCh.py35
-rw-r--r--module/plugins/accounts/CzshareCom.py37
-rw-r--r--module/plugins/accounts/DdlstorageCom.py54
-rw-r--r--module/plugins/accounts/DebridItaliaCom.py58
-rw-r--r--module/plugins/accounts/DepositfilesCom.py25
-rw-r--r--module/plugins/accounts/EasybytezCom.py75
-rw-r--r--module/plugins/accounts/EgoFilesCom.py44
-rw-r--r--module/plugins/accounts/EuroshareEu.py25
-rw-r--r--module/plugins/accounts/FastixRu.py26
-rw-r--r--module/plugins/accounts/FastshareCz.py58
-rw-r--r--module/plugins/accounts/File4safeCom.py18
-rw-r--r--module/plugins/accounts/FileParadoxIn.py16
-rw-r--r--module/plugins/accounts/FilecloudIo.py33
-rw-r--r--module/plugins/accounts/FilefactoryCom.py29
-rw-r--r--module/plugins/accounts/FilejungleCom.py27
-rw-r--r--module/plugins/accounts/FileomCom.py16
-rw-r--r--module/plugins/accounts/FilerNet.py39
-rw-r--r--module/plugins/accounts/FilerioCom.py17
-rw-r--r--module/plugins/accounts/FilesMailRu.py30
-rw-r--r--module/plugins/accounts/FileserveCom.py36
-rw-r--r--module/plugins/accounts/FourSharedCom.py54
-rw-r--r--module/plugins/accounts/FreakshareCom.py60
-rw-r--r--module/plugins/accounts/FreeWayMe.py34
-rw-r--r--module/plugins/accounts/FshareVn.py33
-rw-r--r--module/plugins/accounts/Ftp.py11
-rw-r--r--module/plugins/accounts/HellshareCz.py39
-rw-r--r--module/plugins/accounts/HotfileCom.py89
-rw-r--r--module/plugins/accounts/Http.py11
-rw-r--r--module/plugins/accounts/HugefilesNet.py16
-rw-r--r--module/plugins/accounts/HundredEightyUploadCom.py16
-rw-r--r--module/plugins/accounts/JunocloudMe.py16
-rw-r--r--module/plugins/accounts/Keep2shareCc.py72
-rw-r--r--module/plugins/accounts/LetitbitNet.py27
-rw-r--r--module/plugins/accounts/LinestorageCom.py17
-rw-r--r--module/plugins/accounts/LinksnappyCom.py13
-rw-r--r--module/plugins/accounts/MegaDebridEu.py38
-rw-r--r--module/plugins/accounts/MegaRapidCz.py (renamed from module/plugins/accounts/ShareRapidCom.py)29
-rw-r--r--module/plugins/accounts/MegasharesCom.py10
-rw-r--r--module/plugins/accounts/MovReelCom.py20
-rw-r--r--module/plugins/accounts/MultiDebridCom.py48
-rw-r--r--module/plugins/accounts/MultishareCz.py35
-rw-r--r--module/plugins/accounts/MyfastfileCom.py35
-rwxr-xr-xmodule/plugins/accounts/NetloadIn.py35
-rw-r--r--module/plugins/accounts/NoPremiumPl.py81
-rw-r--r--module/plugins/accounts/NosuploadCom.py16
-rw-r--r--module/plugins/accounts/NovafileCom.py16
-rw-r--r--module/plugins/accounts/NowVideoSx.py56
-rw-r--r--module/plugins/accounts/OboomCom.py60
-rw-r--r--module/plugins/accounts/OneFichierCom.py51
-rw-r--r--module/plugins/accounts/OverLoadMe.py13
-rw-r--r--module/plugins/accounts/Premium4Me.py29
-rw-r--r--module/plugins/accounts/PremiumTo.py34
-rw-r--r--module/plugins/accounts/PremiumizeMe.py21
-rw-r--r--module/plugins/accounts/QuickshareCz.py35
-rw-r--r--module/plugins/accounts/RPNetBiz.py30
-rw-r--r--module/plugins/accounts/RapideoPl.py80
-rw-r--r--module/plugins/accounts/RapidfileshareNet.py18
-rw-r--r--module/plugins/accounts/RapidgatorNet.py29
-rw-r--r--module/plugins/accounts/RapidshareCom.py69
-rw-r--r--module/plugins/accounts/RapiduNet.py47
-rw-r--r--module/plugins/accounts/RarefileNet.py17
-rw-r--r--module/plugins/accounts/RealdebridCom.py25
-rw-r--r--module/plugins/accounts/RehostTo.py38
-rw-r--r--module/plugins/accounts/RyushareCom.py18
-rw-r--r--module/plugins/accounts/SafesharingEu.py16
-rw-r--r--module/plugins/accounts/SecureUploadEu.py16
-rw-r--r--module/plugins/accounts/SendmywayCom.py16
-rw-r--r--module/plugins/accounts/ShareonlineBiz.py81
-rw-r--r--module/plugins/accounts/SimplyPremiumCom.py41
-rw-r--r--module/plugins/accounts/SimplydebridCom.py19
-rw-r--r--module/plugins/accounts/StahnuTo.py31
-rw-r--r--module/plugins/accounts/StreamcloudEu.py16
-rw-r--r--module/plugins/accounts/TurbobitNet.py26
-rw-r--r--module/plugins/accounts/TusfilesNet.py23
-rw-r--r--module/plugins/accounts/UlozTo.py47
-rw-r--r--module/plugins/accounts/UnrestrictLi.py29
-rw-r--r--module/plugins/accounts/UploadcCom.py16
-rw-r--r--module/plugins/accounts/UploadedTo.py80
-rw-r--r--module/plugins/accounts/UploadheroCom.py23
-rw-r--r--module/plugins/accounts/UploadingCom.py76
-rw-r--r--module/plugins/accounts/UptoboxCom.py18
-rw-r--r--module/plugins/accounts/VidPlayNet.py16
-rw-r--r--module/plugins/accounts/WebshareCz.py68
-rw-r--r--module/plugins/accounts/XFileSharingPro.py34
-rw-r--r--module/plugins/accounts/YibaishiwuCom.py25
-rw-r--r--module/plugins/accounts/ZeveraCom.py26
-rw-r--r--module/plugins/captcha/GigasizeCom.py13
-rw-r--r--module/plugins/captcha/LinksaveIn.py25
-rw-r--r--module/plugins/captcha/NetloadIn.py13
-rw-r--r--module/plugins/captcha/ShareonlineBiz.py13
-rw-r--r--module/plugins/captcha/captcha.py119
-rw-r--r--module/plugins/container/CCF.py29
-rw-r--r--module/plugins/container/DLC_25.pycbin8340 -> 8346 bytes
-rw-r--r--module/plugins/container/DLC_26.pycbin8313 -> 8319 bytes
-rw-r--r--module/plugins/container/DLC_27.pycbin8237 -> 8243 bytes
-rw-r--r--module/plugins/container/LinkList.py12
-rw-r--r--module/plugins/container/RSDF.py25
-rw-r--r--module/plugins/crypter/BitshareComFolder.py38
-rw-r--r--module/plugins/crypter/C1neonCom.py16
-rw-r--r--module/plugins/crypter/ChipDe.py20
-rw-r--r--module/plugins/crypter/CloudzillaToFolder.py43
-rw-r--r--module/plugins/crypter/CrockoComFolder.py18
-rw-r--r--module/plugins/crypter/CryptItCom.py16
-rw-r--r--module/plugins/crypter/CzshareComFolder.py21
-rw-r--r--module/plugins/crypter/DDLMusicOrg.py19
-rw-r--r--module/plugins/crypter/DailymotionBatch.py38
-rw-r--r--module/plugins/crypter/DataHuFolder.py62
-rw-r--r--module/plugins/crypter/DdlstorageComFolder.py35
-rw-r--r--module/plugins/crypter/DepositfilesComFolder.py18
-rw-r--r--module/plugins/crypter/Dereferer.py41
-rw-r--r--module/plugins/crypter/DevhostStFolder.py61
-rw-r--r--module/plugins/crypter/DlProtectCom.py34
-rw-r--r--module/plugins/crypter/DontKnowMe.py28
-rw-r--r--module/plugins/crypter/DuckCryptInfo.py46
-rw-r--r--module/plugins/crypter/DuploadOrgFolder.py34
-rw-r--r--module/plugins/crypter/EasybytezComFolder.py57
-rw-r--r--module/plugins/crypter/EmbeduploadCom.py29
-rw-r--r--module/plugins/crypter/FilebeerInfoFolder.py16
-rw-r--r--module/plugins/crypter/FilecloudIoFolder.py38
-rw-r--r--module/plugins/crypter/FilecryptCc.py170
-rw-r--r--module/plugins/crypter/FilefactoryComFolder.py24
-rw-r--r--module/plugins/crypter/FilerNetFolder.py21
-rw-r--r--module/plugins/crypter/FileserveComFolder.py19
-rw-r--r--module/plugins/crypter/FilesonicComFolder.py18
-rw-r--r--module/plugins/crypter/FilestubeCom.py36
-rw-r--r--module/plugins/crypter/FiletramCom.py39
-rw-r--r--module/plugins/crypter/FiredriveComFolder.py41
-rw-r--r--module/plugins/crypter/FourChanOrg.py18
-rw-r--r--module/plugins/crypter/FreakhareComFolder.py38
-rw-r--r--module/plugins/crypter/FreetexthostCom.py33
-rw-r--r--module/plugins/crypter/FshareVnFolder.py18
-rw-r--r--module/plugins/crypter/Go4UpCom.py49
-rw-r--r--module/plugins/crypter/GooGl.py29
-rw-r--r--module/plugins/crypter/HoerbuchIn.py30
-rw-r--r--module/plugins/crypter/HotfileComFolder.py19
-rw-r--r--module/plugins/crypter/HotfileFolderCom.py30
-rw-r--r--module/plugins/crypter/ILoadTo.py16
-rw-r--r--module/plugins/crypter/ImgurComAlbum.py20
-rw-r--r--module/plugins/crypter/JunocloudMeFolder.py23
-rw-r--r--module/plugins/crypter/LetitbitNetFolder.py23
-rw-r--r--module/plugins/crypter/LinkCryptWs.py327
-rw-r--r--module/plugins/crypter/LinkSaveIn.py230
-rw-r--r--module/plugins/crypter/LinkdecrypterCom.py48
-rw-r--r--module/plugins/crypter/LixIn.py43
-rw-r--r--module/plugins/crypter/LofCc.py16
-rw-r--r--module/plugins/crypter/MBLinkInfo.py15
-rw-r--r--module/plugins/crypter/MediafireComFolder.py30
-rw-r--r--module/plugins/crypter/MegaRapidCzFolder.py23
-rw-r--r--module/plugins/crypter/MegauploadComFolder.py18
-rw-r--r--module/plugins/crypter/Movie2kTo.py16
-rw-r--r--module/plugins/crypter/MultiUpOrg.py37
-rw-r--r--module/plugins/crypter/MultiloadCz.py22
-rw-r--r--module/plugins/crypter/MultiuploadCom.py67
-rw-r--r--module/plugins/crypter/NCryptIn.py72
-rw-r--r--module/plugins/crypter/NetfolderIn.py48
-rw-r--r--module/plugins/crypter/NosvideoCom.py22
-rw-r--r--module/plugins/crypter/OneKhDe.py21
-rwxr-xr-xmodule/plugins/crypter/OronComFolder.py16
-rw-r--r--module/plugins/crypter/PastebinCom.py36
-rw-r--r--module/plugins/crypter/QuickshareCzFolder.py24
-rw-r--r--module/plugins/crypter/RSLayerCom.py16
-rw-r--r--module/plugins/crypter/RapidfileshareNetFolder.py23
-rw-r--r--module/plugins/crypter/RelinkUs.py116
-rw-r--r--module/plugins/crypter/SafelinkingNet.py47
-rw-r--r--module/plugins/crypter/SecuredIn.py16
-rw-r--r--module/plugins/crypter/SerienjunkiesOrg.py323
-rw-r--r--module/plugins/crypter/SexuriaCom.py94
-rw-r--r--module/plugins/crypter/ShareLinksBiz.py75
-rw-r--r--module/plugins/crypter/ShareRapidComFolder.py17
-rw-r--r--module/plugins/crypter/SharingmatrixComFolder.py18
-rw-r--r--module/plugins/crypter/SpeedLoadOrgFolder.py30
-rw-r--r--module/plugins/crypter/StealthTo.py16
-rw-r--r--module/plugins/crypter/TnyCz.py35
-rw-r--r--module/plugins/crypter/TrailerzoneInfo.py16
-rw-r--r--module/plugins/crypter/TurbobitNetFolder.py38
-rw-r--r--module/plugins/crypter/TusfilesNetFolder.py48
-rw-r--r--module/plugins/crypter/UlozToFolder.py25
-rw-r--r--module/plugins/crypter/UploadableChFolder.py27
-rw-r--r--module/plugins/crypter/UploadedToFolder.py55
-rw-r--r--module/plugins/crypter/WiiReloadedOrg.py14
-rw-r--r--module/plugins/crypter/WuploadComFolder.py18
-rw-r--r--module/plugins/crypter/XFileSharingProFolder.py50
-rw-r--r--module/plugins/crypter/XupPl.py16
-rw-r--r--module/plugins/crypter/YoutubeBatch.py49
-rw-r--r--module/plugins/hooks/AlldebridCom.py21
-rw-r--r--module/plugins/hooks/BypassCaptcha.py85
-rwxr-xr-xmodule/plugins/hooks/Captcha9kw.py339
-rw-r--r--module/plugins/hooks/CaptchaBrotherhood.py97
-rw-r--r--module/plugins/hooks/Checksum.py99
-rw-r--r--module/plugins/hooks/ClickAndLoad.py70
-rw-r--r--module/plugins/hooks/DeathByCaptcha.py118
-rw-r--r--module/plugins/hooks/DebridItaliaCom.py51
-rw-r--r--module/plugins/hooks/DeleteFinished.py45
-rw-r--r--module/plugins/hooks/DownloadScheduler.py46
-rw-r--r--module/plugins/hooks/EasybytezCom.py34
-rw-r--r--module/plugins/hooks/Ev0InFetcher.py94
-rw-r--r--module/plugins/hooks/ExpertDecoders.py70
-rw-r--r--module/plugins/hooks/ExternalScripts.py104
-rw-r--r--module/plugins/hooks/ExtractArchive.py336
-rw-r--r--module/plugins/hooks/FastixRu.py26
-rw-r--r--module/plugins/hooks/FreeWayMe.py36
-rw-r--r--module/plugins/hooks/HotFolder.py90
-rw-r--r--module/plugins/hooks/IRCInterface.py118
-rw-r--r--module/plugins/hooks/ImageTyperz.py105
-rw-r--r--module/plugins/hooks/LinkdecrypterCom.py49
-rw-r--r--module/plugins/hooks/LinksnappyCom.py21
-rw-r--r--module/plugins/hooks/MegaDebridEu.py39
-rw-r--r--module/plugins/hooks/MergeFiles.py109
-rw-r--r--module/plugins/hooks/MultiDebridCom.py43
-rw-r--r--module/plugins/hooks/MultiHome.py43
-rw-r--r--module/plugins/hooks/MultishareCz.py18
-rw-r--r--module/plugins/hooks/MyfastfileCom.py28
-rw-r--r--module/plugins/hooks/NoPremiumPl.py31
-rw-r--r--module/plugins/hooks/OverLoadMe.py22
-rw-r--r--module/plugins/hooks/Premium4Me.py34
-rw-r--r--module/plugins/hooks/PremiumTo.py37
-rw-r--r--module/plugins/hooks/PremiumizeMe.py31
-rw-r--r--module/plugins/hooks/RPNetBiz.py30
-rw-r--r--module/plugins/hooks/RapideoPl.py31
-rw-r--r--module/plugins/hooks/RealdebridCom.py17
-rw-r--r--module/plugins/hooks/RehostTo.py25
-rw-r--r--module/plugins/hooks/RestartFailed.py40
-rw-r--r--module/plugins/hooks/RestartSlow.py61
-rw-r--r--module/plugins/hooks/SimplyPremiumCom.py30
-rw-r--r--module/plugins/hooks/SimplydebridCom.py19
-rw-r--r--module/plugins/hooks/SkipRev.py108
-rw-r--r--module/plugins/hooks/UnSkipOnFail.py152
-rw-r--r--module/plugins/hooks/UnrestrictLi.py37
-rw-r--r--module/plugins/hooks/UpdateManager.py209
-rw-r--r--module/plugins/hooks/WindowsPhoneToastNotify.py40
-rw-r--r--module/plugins/hooks/XFileSharingPro.py173
-rw-r--r--module/plugins/hooks/XMPPInterface.py66
-rw-r--r--module/plugins/hooks/ZeveraCom.py19
-rw-r--r--module/plugins/hoster/AlldebridCom.py99
-rw-r--r--module/plugins/hoster/BasePlugin.py136
-rw-r--r--module/plugins/hoster/BayfilesCom.py93
-rw-r--r--module/plugins/hoster/BezvadataCz.py60
-rw-r--r--module/plugins/hoster/BillionuploadsCom.py25
-rw-r--r--module/plugins/hoster/BitshareCom.py116
-rw-r--r--module/plugins/hoster/BoltsharingCom.py12
-rw-r--r--module/plugins/hoster/CatShareNet.py66
-rw-r--r--module/plugins/hoster/CloudzerNet.py14
-rw-r--r--module/plugins/hoster/CloudzillaTo.py61
-rw-r--r--module/plugins/hoster/CramitIn.py27
-rw-r--r--module/plugins/hoster/CrockoCom.py53
-rw-r--r--module/plugins/hoster/CyberlockerCh.py12
-rw-r--r--module/plugins/hoster/CzshareCom.py92
-rw-r--r--module/plugins/hoster/DailymotionCom.py82
-rw-r--r--module/plugins/hoster/DataHu.py52
-rw-r--r--module/plugins/hoster/DataportCz.py48
-rw-r--r--module/plugins/hoster/DateiTo.py74
-rw-r--r--module/plugins/hoster/DdlstorageCom.py90
-rw-r--r--module/plugins/hoster/DebridItaliaCom.py76
-rw-r--r--module/plugins/hoster/DepositfilesCom.py65
-rw-r--r--module/plugins/hoster/DevhostSt.py48
-rw-r--r--module/plugins/hoster/DlFreeFr.py130
-rw-r--r--module/plugins/hoster/DodanePl.py18
-rw-r--r--module/plugins/hoster/DropboxCom.py42
-rw-r--r--module/plugins/hoster/DuploadOrg.py34
-rw-r--r--module/plugins/hoster/EasybytezCom.py41
-rw-r--r--module/plugins/hoster/EdiskCz.py42
-rw-r--r--module/plugins/hoster/EgoFilesCom.py99
-rw-r--r--module/plugins/hoster/EnteruploadCom.py18
-rw-r--r--module/plugins/hoster/EpicShareNet.py22
-rw-r--r--module/plugins/hoster/EuroshareEu.py43
-rw-r--r--module/plugins/hoster/ExtabitCom.py65
-rw-r--r--module/plugins/hoster/FastixRu.py83
-rw-r--r--module/plugins/hoster/FastshareCz.py104
-rw-r--r--module/plugins/hoster/File4safeCom.py36
-rw-r--r--module/plugins/hoster/FileApeCom.py12
-rw-r--r--module/plugins/hoster/FileParadoxIn.py22
-rw-r--r--module/plugins/hoster/FileSharkPl.py140
-rw-r--r--module/plugins/hoster/FileStoreTo.py37
-rw-r--r--module/plugins/hoster/FilebeerInfo.py12
-rw-r--r--module/plugins/hoster/FilecloudIo.py132
-rw-r--r--module/plugins/hoster/FilefactoryCom.py116
-rw-r--r--module/plugins/hoster/FilejungleCom.py28
-rw-r--r--module/plugins/hoster/FileomCom.py47
-rw-r--r--module/plugins/hoster/FilepostCom.py125
-rw-r--r--module/plugins/hoster/FilepupNet.py51
-rw-r--r--module/plugins/hoster/FilerNet.py114
-rw-r--r--module/plugins/hoster/FilerioCom.py25
-rw-r--r--module/plugins/hoster/FilesMailRu.py31
-rw-r--r--module/plugins/hoster/FileserveCom.py141
-rw-r--r--module/plugins/hoster/FileshareInUa.py81
-rw-r--r--module/plugins/hoster/FilesonicCom.py19
-rw-r--r--module/plugins/hoster/FilezyNet.py36
-rw-r--r--module/plugins/hoster/FiredriveCom.py61
-rw-r--r--module/plugins/hoster/FlyFilesNet.py28
-rw-r--r--module/plugins/hoster/FourSharedCom.py32
-rw-r--r--module/plugins/hoster/FreakshareCom.py50
-rw-r--r--module/plugins/hoster/FreeWayMe.py49
-rw-r--r--module/plugins/hoster/FreevideoCz.py10
-rw-r--r--module/plugins/hoster/FshareVn.py67
-rw-r--r--module/plugins/hoster/Ftp.py58
-rw-r--r--module/plugins/hoster/GamefrontCom.py34
-rw-r--r--module/plugins/hoster/GigapetaCom.py51
-rw-r--r--module/plugins/hoster/GooIm.py54
-rw-r--r--module/plugins/hoster/HellshareCz.py46
-rw-r--r--module/plugins/hoster/HellspyCz.py27
-rw-r--r--module/plugins/hoster/HotfileCom.py15
-rw-r--r--module/plugins/hoster/HugefilesNet.py48
-rw-r--r--module/plugins/hoster/HundredEightyUploadCom.py40
-rw-r--r--module/plugins/hoster/IFileWs.py21
-rw-r--r--module/plugins/hoster/IcyFilesCom.py27
-rw-r--r--module/plugins/hoster/IfileIt.py72
-rw-r--r--module/plugins/hoster/IfolderRu.py48
-rw-r--r--module/plugins/hoster/JumbofilesCom.py22
-rw-r--r--module/plugins/hoster/JunocloudMe.py26
-rw-r--r--module/plugins/hoster/Keep2shareCC.py121
-rw-r--r--module/plugins/hoster/Keep2shareCc.py130
-rw-r--r--module/plugins/hoster/KickloadCom.py18
-rw-r--r--module/plugins/hoster/KingfilesNet.py82
-rw-r--r--module/plugins/hoster/LemUploadsCom.py24
-rw-r--r--module/plugins/hoster/LetitbitNet.py127
-rw-r--r--module/plugins/hoster/LinestorageCom.py21
-rw-r--r--module/plugins/hoster/LinksnappyCom.py83
-rw-r--r--module/plugins/hoster/LoadTo.py67
-rw-r--r--module/plugins/hoster/LomafileCom.py58
-rw-r--r--module/plugins/hoster/LuckyShareNet.py53
-rw-r--r--module/plugins/hoster/MediafireCom.py112
-rw-r--r--module/plugins/hoster/MegaCoNz.py (renamed from module/plugins/hoster/MegaNz.py)87
-rw-r--r--module/plugins/hoster/MegaDebridEu.py80
-rw-r--r--module/plugins/hoster/MegaFilesSe.py21
-rw-r--r--module/plugins/hoster/MegaRapidCz.py (renamed from module/plugins/hoster/ShareRapidCom.py)35
-rw-r--r--module/plugins/hoster/MegacrypterCom.py28
-rw-r--r--module/plugins/hoster/MegareleaseOrg.py35
-rw-r--r--module/plugins/hoster/MegasharesCom.py107
-rw-r--r--module/plugins/hoster/MegauploadCom.py18
-rw-r--r--module/plugins/hoster/MegavideoCom.py19
-rw-r--r--module/plugins/hoster/MovReelCom.py26
-rw-r--r--module/plugins/hoster/MultiDebridCom.py56
-rw-r--r--module/plugins/hoster/MultishareCz.py79
-rw-r--r--module/plugins/hoster/MyfastfileCom.py42
-rw-r--r--module/plugins/hoster/MyvideoDe.py22
-rw-r--r--module/plugins/hoster/NahrajCz.py18
-rw-r--r--module/plugins/hoster/NarodRu.py52
-rw-r--r--module/plugins/hoster/NetloadIn.py218
-rw-r--r--module/plugins/hoster/NoPremiumPl.py104
-rw-r--r--module/plugins/hoster/NosuploadCom.py27
-rw-r--r--module/plugins/hoster/NovafileCom.py31
-rw-r--r--module/plugins/hoster/NowDownloadEu.py72
-rw-r--r--module/plugins/hoster/NowDownloadSx.py64
-rw-r--r--module/plugins/hoster/NowVideoSx.py44
-rw-r--r--module/plugins/hoster/OboomCom.py85
-rw-r--r--module/plugins/hoster/OneFichierCom.py85
-rw-r--r--module/plugins/hoster/OronCom.py19
-rw-r--r--module/plugins/hoster/OverLoadMe.py84
-rw-r--r--module/plugins/hoster/PandaPlanet.py26
-rw-r--r--module/plugins/hoster/PandaplaNet.py18
-rw-r--r--module/plugins/hoster/PornhostCom.py26
-rw-r--r--module/plugins/hoster/PornhubCom.py22
-rw-r--r--module/plugins/hoster/PotloadCom.py20
-rw-r--r--module/plugins/hoster/Premium4Me.py70
-rw-r--r--module/plugins/hoster/PremiumTo.py64
-rw-r--r--module/plugins/hoster/PremiumizeMe.py57
-rw-r--r--module/plugins/hoster/PromptfileCom.py45
-rw-r--r--module/plugins/hoster/PrzeklejPl.py18
-rw-r--r--module/plugins/hoster/QuickshareCz.py57
-rw-r--r--module/plugins/hoster/RPNetBiz.py117
-rw-r--r--module/plugins/hoster/RapideoPl.py102
-rw-r--r--module/plugins/hoster/RapidfileshareNet.py31
-rw-r--r--module/plugins/hoster/RapidgatorNet.py115
-rw-r--r--module/plugins/hoster/RapidshareCom.py227
-rw-r--r--module/plugins/hoster/RapiduNet.py82
-rw-r--r--module/plugins/hoster/RarefileNet.py35
-rw-r--r--module/plugins/hoster/RealdebridCom.py96
-rw-r--r--module/plugins/hoster/RedtubeCom.py18
-rw-r--r--module/plugins/hoster/RehostTo.py39
-rw-r--r--module/plugins/hoster/RemixshareCom.py31
-rw-r--r--module/plugins/hoster/RgHostNet.py26
-rw-r--r--module/plugins/hoster/RyushareCom.py48
-rw-r--r--module/plugins/hoster/SafesharingEu.py23
-rw-r--r--module/plugins/hoster/SecureUploadEu.py24
-rw-r--r--module/plugins/hoster/SendmywayCom.py24
-rw-r--r--module/plugins/hoster/SendspaceCom.py47
-rw-r--r--module/plugins/hoster/Share4webCom.py17
-rw-r--r--module/plugins/hoster/Share76Com.py12
-rw-r--r--module/plugins/hoster/ShareFilesCo.py12
-rw-r--r--module/plugins/hoster/SharebeesCom.py12
-rw-r--r--module/plugins/hoster/ShareonlineBiz.py233
-rw-r--r--module/plugins/hoster/ShareplaceCom.py28
-rw-r--r--module/plugins/hoster/SharingmatrixCom.py19
-rw-r--r--module/plugins/hoster/ShragleCom.py13
-rw-r--r--module/plugins/hoster/SimplyPremiumCom.py142
-rw-r--r--module/plugins/hoster/SimplydebridCom.py78
-rw-r--r--module/plugins/hoster/SockshareCom.py86
-rw-r--r--module/plugins/hoster/SoundcloudCom.py31
-rw-r--r--module/plugins/hoster/SpeedLoadOrg.py12
-rw-r--r--module/plugins/hoster/SpeedfileCz.py27
-rw-r--r--module/plugins/hoster/SpeedyshareCom.py51
-rw-r--r--module/plugins/hoster/StorageTo.py18
-rw-r--r--module/plugins/hoster/StreamCz.py46
-rw-r--r--module/plugins/hoster/StreamcloudEu.py119
-rw-r--r--module/plugins/hoster/TurbobitNet.py116
-rw-r--r--module/plugins/hoster/TurbouploadCom.py27
-rw-r--r--module/plugins/hoster/TusfilesNet.py55
-rw-r--r--module/plugins/hoster/TwoSharedCom.py30
-rw-r--r--module/plugins/hoster/UlozTo.py105
-rw-r--r--module/plugins/hoster/UloziskoSk.py48
-rw-r--r--module/plugins/hoster/UnibytesCom.py48
-rw-r--r--module/plugins/hoster/UnrestrictLi.py131
-rw-r--r--module/plugins/hoster/UpleaCom.py61
-rw-r--r--module/plugins/hoster/UploadStationCom.py13
-rw-r--r--module/plugins/hoster/UploadableCh.py90
-rw-r--r--module/plugins/hoster/UploadboxCom.py18
-rw-r--r--module/plugins/hoster/UploadedTo.py89
-rw-r--r--module/plugins/hoster/UploadhereCom.py18
-rw-r--r--module/plugins/hoster/UploadheroCom.py58
-rw-r--r--module/plugins/hoster/UploadingCom.py88
-rw-r--r--module/plugins/hoster/UploadkingCom.py18
-rw-r--r--module/plugins/hoster/UpstoreNet.py41
-rw-r--r--module/plugins/hoster/UptoboxCom.py83
-rw-r--r--module/plugins/hoster/VeehdCom.py30
-rw-r--r--module/plugins/hoster/VeohCom.py45
-rw-r--r--module/plugins/hoster/VidPlayNet.py25
-rw-r--r--module/plugins/hoster/VimeoCom.py55
-rw-r--r--module/plugins/hoster/Vipleech4uCom.py12
-rw-r--r--module/plugins/hoster/WarserverCz.py12
-rw-r--r--module/plugins/hoster/WebshareCz.py97
-rw-r--r--module/plugins/hoster/WrzucTo.py43
-rw-r--r--module/plugins/hoster/WuploadCom.py13
-rw-r--r--module/plugins/hoster/X7To.py12
-rw-r--r--module/plugins/hoster/XFileSharingPro.py342
-rw-r--r--module/plugins/hoster/XHamsterCom.py46
-rw-r--r--module/plugins/hoster/XVideosCom.py19
-rw-r--r--module/plugins/hoster/Xdcc.py77
-rw-r--r--module/plugins/hoster/YibaishiwuCom.py51
-rw-r--r--module/plugins/hoster/YoupornCom.py20
-rw-r--r--module/plugins/hoster/YourfilesTo.py29
-rw-r--r--module/plugins/hoster/YoutubeCom.py75
-rw-r--r--module/plugins/hoster/ZDF.py31
-rw-r--r--module/plugins/hoster/ZShareNet.py19
-rw-r--r--module/plugins/hoster/ZeveraCom.py125
-rw-r--r--module/plugins/hoster/ZippyshareCom.py84
-rw-r--r--module/plugins/internal/CaptchaService.py329
-rw-r--r--module/plugins/internal/DeadCrypter.py29
-rw-r--r--module/plugins/internal/DeadHoster.py33
-rw-r--r--module/plugins/internal/Extractor.py (renamed from module/plugins/internal/AbstractExtractor.py)96
-rw-r--r--module/plugins/internal/MultiHook.py218
-rw-r--r--module/plugins/internal/MultiHoster.py211
-rw-r--r--module/plugins/internal/SimpleCrypter.py164
-rw-r--r--module/plugins/internal/SimpleDereferer.py96
-rw-r--r--module/plugins/internal/SimpleHoster.py667
-rw-r--r--module/plugins/internal/UnRar.py272
-rw-r--r--module/plugins/internal/UnZip.py101
-rw-r--r--module/plugins/internal/XFSAccount.py160
-rw-r--r--module/plugins/internal/XFSCrypter.py29
-rw-r--r--module/plugins/internal/XFSHoster.py341
-rw-r--r--module/plugins/internal/XFSPAccount.py82
466 files changed, 13599 insertions, 11819 deletions
diff --git a/module/plugins/Account.py b/module/plugins/Account.py
index 21f65816a..c147404e0 100644
--- a/module/plugins/Account.py
+++ b/module/plugins/Account.py
@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
-
+
@author: mkaay
"""
@@ -25,7 +25,6 @@ from threading import RLock
from Plugin import Base
from module.utils import compare_time, parseFileSize, lock
-
class WrongPassword(Exception):
pass
@@ -37,16 +36,16 @@ class Account(Base):
associated hoster plugin. Plugin should also provide `loadAccountInfo`
"""
__name__ = "Account"
- __version__ = "0.3"
+ __version__ = "0.2"
__type__ = "account"
- __description__ = """Base account plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __description__ = """Account Plugin"""
+ __author_name__ = ("mkaay")
+ __author_mail__ = ("mkaay@mkaay.de")
- #: after that time (in minutes) pyload will relogin the account
- login_timeout = 10 * 60
- #: after that time (in minutes) account data will be reloaded
- info_threshold = 10 * 60
+ #: after that time [in minutes] pyload will relogin the account
+ login_timeout = 600
+ #: account data will be reloaded after this time
+ info_threshold = 600
def __init__(self, manager, accounts):
@@ -77,7 +76,7 @@ class Account(Base):
def _login(self, user, data):
# set timestamp for login
self.timestamps[user] = time()
-
+
req = self.getAccountRequest(user)
try:
self.login(user, data, req)
@@ -85,20 +84,17 @@ class Account(Base):
self.logWarning(
_("Could not login with account %(user)s | %(msg)s") % {"user": user
, "msg": _("Wrong Password")})
- success = data["valid"] = False
+ data["valid"] = False
+
except Exception, e:
self.logWarning(
_("Could not login with account %(user)s | %(msg)s") % {"user": user
, "msg": e})
- success = data["valid"] = False
+ data["valid"] = False
if self.core.debug:
print_exc()
- else:
- success = True
finally:
- if req:
- req.close()
- return success
+ if req: req.close()
def relogin(self, user):
req = self.getAccountRequest(user)
@@ -108,7 +104,7 @@ class Account(Base):
if user in self.infos:
del self.infos[user] #delete old information
- return self._login(user, self.accounts[user])
+ self._login(user, self.accounts[user])
def setAccounts(self, accounts):
self.accounts = accounts
@@ -288,10 +284,9 @@ class Account(Base):
def checkLogin(self, user):
""" checks if user is still logged in """
if user in self.timestamps:
- if self.login_timeout > 0 and self.timestamps[user] + self.login_timeout * 60 < time():
+ if self.timestamps[user] + self.login_timeout * 60 < time():
self.logDebug("Reached login timeout for %s" % user)
- return self.relogin(user)
- else:
- return True
- else:
- return False
+ self.relogin(user)
+ return False
+
+ return True
diff --git a/module/plugins/AccountManager.py b/module/plugins/AccountManager.py
index 39e613c1a..fc521d36c 100644
--- a/module/plugins/AccountManager.py
+++ b/module/plugins/AccountManager.py
@@ -1,5 +1,5 @@
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
"""
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@ from module.utils import chmod, lock
ACC_VERSION = 1
-
class AccountManager():
"""manages all accounts"""
@@ -48,6 +47,7 @@ class AccountManager():
self.initAccountPlugins()
self.loadAccounts()
+
def getAccountPlugin(self, plugin):
"""get account instance for plugin or None if anonymous"""
if plugin in self.accounts:
@@ -60,22 +60,21 @@ class AccountManager():
def getAccountPlugins(self):
""" get all account instances"""
-
+
plugins = []
for plugin in self.accounts.keys():
plugins.append(self.getAccountPlugin(plugin))
-
+
return plugins
-
#----------------------------------------------------------------------
def loadAccounts(self):
"""loads all accounts available"""
-
+
if not exists("accounts.conf"):
f = open("accounts.conf", "wb")
f.write("version: " + str(ACC_VERSION))
f.close()
-
+
f = open("accounts.conf", "rb")
content = f.readlines()
version = content[0].split(":")[1].strip() if content else ""
@@ -88,58 +87,60 @@ class AccountManager():
f.close()
self.core.log.warning(_("Account settings deleted, due to new config format."))
return
-
+
+
+
plugin = ""
name = ""
-
+
for line in content[1:]:
line = line.strip()
-
+
if not line: continue
if line.startswith("#"): continue
if line.startswith("version"): continue
-
+
if line.endswith(":") and line.count(":") == 1:
plugin = line[:-1]
self.accounts[plugin] = {}
-
+
elif line.startswith("@"):
try:
option = line[1:].split()
- self.accounts[plugin][name]['options'][option[0]] = [] if len(option) < 2 else ([option[1]] if len(option) < 3 else option[1:])
+ self.accounts[plugin][name]["options"][option[0]] = [] if len(option) < 2 else ([option[1]] if len(option) < 3 else option[1:])
except:
pass
-
+
elif ":" in line:
name, sep, pw = line.partition(":")
self.accounts[plugin][name] = {"password": pw, "options": {}, "valid": True}
-
#----------------------------------------------------------------------
def saveAccounts(self):
"""save all account information"""
-
+
f = open("accounts.conf", "wb")
f.write("version: " + str(ACC_VERSION) + "\n")
-
+
for plugin, accounts in self.accounts.iteritems():
f.write("\n")
f.write(plugin+":\n")
-
+
for name,data in accounts.iteritems():
- f.write("\n\t%s:%s\n" % (name,data['password']) )
- if data['options']:
- for option, values in data['options'].iteritems():
+ f.write("\n\t%s:%s\n" % (name,data["password"]) )
+ if data["options"]:
+ for option, values in data["options"].iteritems():
f.write("\t@%s %s\n" % (option, " ".join(values)))
-
+
f.close()
chmod(f.name, 0600)
-
+
+
#----------------------------------------------------------------------
def initAccountPlugins(self):
"""init names"""
for name in self.core.pluginManager.getAccountPlugins():
self.accounts[name] = {}
-
+
@lock
def updateAccount(self, plugin , user, password=None, options={}):
"""add or update account"""
@@ -147,14 +148,14 @@ class AccountManager():
p = self.getAccountPlugin(plugin)
updated = p.updateAccounts(user, password, options)
#since accounts is a ref in plugin self.accounts doesnt need to be updated here
-
+
self.saveAccounts()
if updated: p.scheduleRefresh(user, force=False)
-
+
@lock
def removeAccount(self, plugin, user):
"""remove account"""
-
+
if plugin in self.accounts:
p = self.getAccountPlugin(plugin)
p.removeAccount(user)
@@ -168,7 +169,7 @@ class AccountManager():
if refresh:
self.core.scheduler.addJob(0, self.core.accountManager.getAccountInfos)
force = False
-
+
for p in self.accounts.keys():
if self.accounts[p]:
p = self.getAccountPlugin(p)
@@ -178,7 +179,7 @@ class AccountManager():
e = AccountUpdateEvent()
self.core.pullManager.addEvent(e)
return data
-
+
def sendChange(self):
e = AccountUpdateEvent()
self.core.pullManager.addEvent(e)
diff --git a/module/plugins/Container.py b/module/plugins/Container.py
index ed201e2e4..c233d3710 100644
--- a/module/plugins/Container.py
+++ b/module/plugins/Container.py
@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
-
+
@author: mkaay
"""
@@ -23,15 +23,14 @@ from os.path import join, exists, basename
from os import remove
import re
-
class Container(Crypter):
__name__ = "Container"
__version__ = "0.1"
__pattern__ = None
__type__ = "container"
- __description__ = """Base container decrypter plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __description__ = """Base container plugin"""
+ __author_name__ = ("mkaay")
+ __author_mail__ = ("mkaay@mkaay.de")
def preprocessing(self, thread):
@@ -39,27 +38,27 @@ class Container(Crypter):
self.setup()
self.thread = thread
-
+
self.loadToDisk()
self.decrypt(self.pyfile)
self.deleteTmp()
-
+
self.createPackages()
-
+
def loadToDisk(self):
"""loads container to disk if its stored remotely and overwrite url,
or check existent on several places at disk"""
-
+
if self.pyfile.url.startswith("http"):
self.pyfile.name = re.findall("([^\/=]+)", self.pyfile.url)[-1]
content = self.load(self.pyfile.url)
- self.pyfile.url = join(self.config['general']['download_folder'], self.pyfile.name)
+ self.pyfile.url = join(self.config["general"]["download_folder"], self.pyfile.name)
f = open(self.pyfile.url, "wb" )
f.write(content)
f.close()
-
+
else:
self.pyfile.name = basename(self.pyfile.url)
if not exists(self.pyfile.url):
@@ -67,8 +66,10 @@ class Container(Crypter):
self.pyfile.url = join(pypath, self.pyfile.url)
else:
self.fail(_("File not exists."))
-
+
def deleteTmp(self):
if self.pyfile.name.startswith("tmp_"):
remove(self.pyfile.url)
+
+
diff --git a/module/plugins/Crypter.py b/module/plugins/Crypter.py
index b613ff023..d1549fe80 100644
--- a/module/plugins/Crypter.py
+++ b/module/plugins/Crypter.py
@@ -13,34 +13,33 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
-
+
@author: mkaay
"""
from module.plugins.Plugin import Plugin
-
class Crypter(Plugin):
__name__ = "Crypter"
__version__ = "0.1"
__pattern__ = None
- __type__ = "crypter"
- __description__ = """Base decrypter plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
-
+ __type__ = "container"
+ __description__ = """Base crypter plugin"""
+ __author_name__ = ("mkaay")
+ __author_mail__ = ("mkaay@mkaay.de")
+
def __init__(self, pyfile):
Plugin.__init__(self, pyfile)
-
+
#: Put all packages here. It's a list of tuples like: ( name, [list of links], folder )
self.packages = []
#: List of urls, pyLoad will generate packagenames
self.urls = []
-
+
self.multiDL = True
self.limitDL = 0
-
+
def preprocessing(self, thread):
"""prepare"""
@@ -48,9 +47,9 @@ class Crypter(Plugin):
self.thread = thread
self.decrypt(self.pyfile)
-
+
self.createPackages()
-
+
def decrypt(self, pyfile):
raise NotImplementedError
@@ -60,9 +59,9 @@ class Crypter(Plugin):
for pack in self.packages:
self.log.debug("Parsed package %(name)s with %(len)d links" % { "name" : pack[0], "len" : len(pack[1]) } )
-
+
links = [x.decode("utf-8") for x in pack[1]]
-
+
pid = self.core.api.addPackage(pack[0], links, self.pyfile.package().queue)
if self.pyfile.package().password:
@@ -70,3 +69,4 @@ class Crypter(Plugin):
if self.urls:
self.core.api.generateAndAddPackages(self.urls)
+
diff --git a/module/plugins/Hook.py b/module/plugins/Hook.py
index b9c7b832f..5efd08bae 100644
--- a/module/plugins/Hook.py
+++ b/module/plugins/Hook.py
@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
-
+
@author: mkaay
@interface-version: 0.2
"""
@@ -22,7 +22,6 @@ from traceback import print_exc
from Plugin import Base
-
class Expose(object):
""" used for decoration to declare rpc services """
@@ -30,14 +29,11 @@ class Expose(object):
hookManager.addRPC(f.__module__, f.func_name, f.func_doc)
return f
-
def threaded(f):
-
def run(*args,**kwargs):
hookManager.startThread(f, *args, **kwargs)
return run
-
class Hook(Base):
"""
Base class for hook plugins.
@@ -46,8 +42,8 @@ class Hook(Base):
__version__ = "0.2"
__type__ = "hook"
__threaded__ = []
- __config__ = [("name", "type", "desc", "default")]
- __description__ = """Interface for hook"""
+ __config__ = [ ("name", "type", "desc" , "default") ]
+ __description__ = """interface for hook"""
__author_name__ = ("mkaay", "RaNaN")
__author_mail__ = ("mkaay@mkaay.de", "RaNaN@pyload.org")
@@ -112,7 +108,7 @@ class Hook(Base):
def __repr__(self):
return "<Hook %s>" % self.__name__
-
+
def setup(self):
""" more init stuff if needed """
pass
@@ -120,11 +116,11 @@ class Hook(Base):
def unload(self):
""" called when hook was deactivated """
pass
-
+
def isActivated(self):
""" checks if hook is activated"""
return self.config.getPlugin(self.__name__, "activated")
-
+
#event methods - overwrite these if needed
def coreReady(self):
@@ -132,25 +128,25 @@ class Hook(Base):
def coreExiting(self):
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
@@ -162,4 +158,4 @@ class Hook(Base):
pass
def captchaInvalid(self, task):
- pass
+ pass \ No newline at end of file
diff --git a/module/plugins/Hoster.py b/module/plugins/Hoster.py
index 67692a94f..814a70949 100644
--- a/module/plugins/Hoster.py
+++ b/module/plugins/Hoster.py
@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
-
+
@author: mkaay
"""
@@ -23,12 +23,11 @@ def getInfo(self):
#result = [ .. (name, size, status, url) .. ]
return
-
class Hoster(Plugin):
__name__ = "Hoster"
__version__ = "0.1"
__pattern__ = None
__type__ = "hoster"
__description__ = """Base hoster plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __author_name__ = ("mkaay")
+ __author_mail__ = ("mkaay@mkaay.de")
diff --git a/module/plugins/Plugin.py b/module/plugins/Plugin.py
index 8722496b5..15bf3971f 100644
--- a/module/plugins/Plugin.py
+++ b/module/plugins/Plugin.py
@@ -146,7 +146,7 @@ class Plugin(Base):
__pattern__ = None
__type__ = "hoster"
__config__ = [("name", "type", "desc", "default")]
- __description__ = """Base plugin"""
+ __description__ = """Base Plugin"""
__author_name__ = ("RaNaN", "spoob", "mkaay")
__author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "mkaay@mkaay.de")
@@ -207,8 +207,8 @@ class Plugin(Base):
def getChunkCount(self):
if self.chunkLimit <= 0:
- return self.config['download']['chunks']
- return min(self.config['download']['chunks'], self.chunkLimit)
+ return self.config["download"]["chunks"]
+ return min(self.config["download"]["chunks"], self.chunkLimit)
def __call__(self):
return self.__name__
@@ -263,7 +263,7 @@ class Plugin(Base):
def setWait(self, seconds, reconnect=False):
"""Set a specific wait time later used with `wait`
-
+
:param seconds: wait time in seconds
:param reconnect: True if a reconnect would avoid wait time
"""
@@ -339,7 +339,7 @@ class Plugin(Base):
:param result_type: 'textual' if text is written on the captcha\
or 'positional' for captcha where the user have to click\
on a specific region on the captcha
-
+
:return: result of decrypting
"""
@@ -478,12 +478,12 @@ class Plugin(Base):
location = save_join(download_folder, self.pyfile.package().folder)
if not exists(location):
- makedirs(location, int(self.core.config['permission']['folder'], 8))
+ makedirs(location, int(self.core.config["permission"]["folder"], 8))
- if self.core.config['permission']['change_dl'] and os.name != "nt":
+ if self.core.config["permission"]["change_dl"] and os.name != "nt":
try:
- uid = getpwnam(self.config['permission']['user'])[2]
- gid = getgrnam(self.config['permission']['group'])[2]
+ uid = getpwnam(self.config["permission"]["user"])[2]
+ gid = getgrnam(self.config["permission"]["group"])[2]
chown(location, uid, gid)
except Exception, e:
@@ -511,13 +511,13 @@ class Plugin(Base):
fs_filename = fs_encode(filename)
- if self.core.config['permission']['change_file']:
- chmod(fs_filename, int(self.core.config['permission']['file'], 8))
+ if self.core.config["permission"]["change_file"]:
+ chmod(fs_filename, int(self.core.config["permission"]["file"], 8))
- if self.core.config['permission']['change_dl'] and os.name != "nt":
+ if self.core.config["permission"]["change_dl"] and os.name != "nt":
try:
- uid = getpwnam(self.config['permission']['user'])[2]
- gid = getgrnam(self.config['permission']['group'])[2]
+ uid = getpwnam(self.config["permission"]["user"])[2]
+ gid = getgrnam(self.config["permission"]["group"])[2]
chown(fs_filename, uid, gid)
except Exception, e:
@@ -528,7 +528,7 @@ class Plugin(Base):
def checkDownload(self, rules, api_size=0, max_size=50000, delete=True, read_size=0):
""" checks the content of the last downloaded file, re match is saved to `lastCheck`
-
+
:param rules: dict with names and rules to match (compiled regexp or strings)
:param api_size: expected file size
:param max_size: if the file is larger then it wont be checked
diff --git a/module/plugins/PluginManager.py b/module/plugins/PluginManager.py
index b290c2746..f3f5f47bc 100644
--- a/module/plugins/PluginManager.py
+++ b/module/plugins/PluginManager.py
@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
-
+
@author: mkaay, RaNaN
"""
@@ -29,7 +29,6 @@ from traceback import print_exc
from module.lib.SafeEval import const_eval as literal_eval
from module.ConfigParser import IGNORE
-
class PluginManager:
ROOT = "module.plugins."
USERROOT = "userplugins."
@@ -80,11 +79,11 @@ class PluginManager:
"""
returns dict with information
home contains parsed plugins from module.
-
+
{
name : {path, version, config, (pattern, re), (plugin, class)}
}
-
+
"""
plugins = {}
if home:
@@ -372,9 +371,10 @@ if __name__ == "__main__":
a = time()
- test = ["http://www.youtube.com/watch?v=%s" % x for x in xrange(0, 100)]
+ test = ["http://www.youtube.com/watch?v=%s" % x for x in range(0, 100)]
print p.parseUrls(test)
b = time()
print b - a, "s"
+
diff --git a/module/plugins/ReCaptcha.py b/module/plugins/ReCaptcha.py
deleted file mode 100644
index 143ecfb83..000000000
--- a/module/plugins/ReCaptcha.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-
-
-class ReCaptcha():
-
- def __init__(self, plugin):
- self.plugin = plugin
-
- def challenge(self, id):
- js = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={"k":id}, cookies=True)
-
- try:
- challenge = re.search("challenge : '(.*?)',", js).group(1)
- server = re.search("server : '(.*?)',", js).group(1)
- except:
- self.plugin.fail("recaptcha error")
- result = self.result(server,challenge)
-
- return challenge, result
-
- def result(self, server, challenge):
- return self.plugin.decryptCaptcha("%simage"%server, get={"c":challenge}, cookies=True, imgtype="jpg")
diff --git a/module/plugins/accounts/AlldebridCom.py b/module/plugins/accounts/AlldebridCom.py
index 122d23447..8fb841a39 100644
--- a/module/plugins/accounts/AlldebridCom.py
+++ b/module/plugins/accounts/AlldebridCom.py
@@ -1,29 +1,31 @@
# -*- coding: utf-8 -*-
+import re
import xml.dom.minidom as dom
+
from time import time
-import re
-import urllib
+from urllib import urlencode
-from module.plugins.Account import Account
from BeautifulSoup import BeautifulSoup
+from module.plugins.Account import Account
+
class AlldebridCom(Account):
- __name__ = "AlldebridCom"
+ __name__ = "AlldebridCom"
+ __type__ = "account"
__version__ = "0.22"
- __type__ = "account"
__description__ = """AllDebrid.com account plugin"""
- __author_name__ = "Andy Voigt"
- __author_mail__ = "spamsales@online.de"
+ __license__ = "GPLv3"
+ __authors__ = [("Andy Voigt", "spamsales@online.de")]
def loadAccountInfo(self, user, req):
data = self.getAccountData(user)
- page = req.load("http://www.alldebrid.com/account/")
- soup = BeautifulSoup(page)
- #Try to parse expiration date directly from the control panel page (better accuracy)
+ html = req.load("http://www.alldebrid.com/account/")
+ soup = BeautifulSoup(html)
+ #Try to parse expiration date directly from the control panel page (better accuracy)
try:
time_text = soup.find('div', attrs={'class': 'remaining_time_text'}).strong.string
self.logDebug("Account expires in: %s" % time_text)
@@ -34,23 +36,24 @@ class AlldebridCom(Account):
#Get expiration date from API
except:
data = self.getAccountData(user)
- page = req.load("http://www.alldebrid.com/api.php?action=info_user&login=%s&pw=%s" % (user,
- data['password']))
- self.logDebug(page)
- xml = dom.parseString(page)
+ html = req.load("http://www.alldebrid.com/api.php",
+ get={'action': "info_user", 'login': user, 'pw': data['password']})
+ self.logDebug(html)
+ xml = dom.parseString(html)
exp_time = time() + int(xml.getElementsByTagName("date")[0].childNodes[0].nodeValue) * 24 * 60 * 60
account_info = {"validuntil": exp_time, "trafficleft": -1}
return account_info
+
def login(self, user, data, req):
- urlparams = urllib.urlencode({'action': 'login', 'login_login': user, 'login_password': data['password']})
- page = req.load("http://www.alldebrid.com/register/?%s" % urlparams)
+ urlparams = urlencode({'action': 'login', 'login_login': user, 'login_password': data['password']})
+ html = req.load("http://www.alldebrid.com/register/?%s" % urlparams)
- if "This login doesn't exist" in page:
+ if "This login doesn't exist" in html:
self.wrongPassword()
- if "The password is not valid" in page:
+ if "The password is not valid" in html:
self.wrongPassword()
- if "Invalid captcha" in page:
+ if "Invalid captcha" in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/BayfilesCom.py b/module/plugins/accounts/BayfilesCom.py
deleted file mode 100644
index 9d497ccb2..000000000
--- a/module/plugins/accounts/BayfilesCom.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-from time import time
-
-from module.plugins.Account import Account
-from module.common.json_layer import json_loads
-
-
-class BayfilesCom(Account):
- __name__ = "BayfilesCom"
- __version__ = "0.03"
- __type__ = "account"
-
- __description__ = """Bayfiles.com account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
-
- def loadAccountInfo(self, user, req):
- for _ in xrange(2):
- response = json_loads(req.load("http://api.bayfiles.com/v1/account/info"))
- self.logDebug(response)
- if not response['error']:
- break
- self.logWarning(response['error'])
- self.relogin(user)
-
- return {"premium": bool(response['premium']), "trafficleft": -1,
- "validuntil": response['expires'] if response['expires'] >= int(time()) else -1}
-
- def login(self, user, data, req):
- response = json_loads(req.load("http://api.bayfiles.com/v1/account/login/%s/%s" % (user, data['password'])))
- self.logDebug(response)
- if response['error']:
- self.logError(response['error'])
- self.wrongPassword()
diff --git a/module/plugins/accounts/BillionuploadsCom.py b/module/plugins/accounts/BillionuploadsCom.py
new file mode 100644
index 000000000..11af36591
--- /dev/null
+++ b/module/plugins/accounts/BillionuploadsCom.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class BillionuploadsCom(XFSAccount):
+ __name__ = "BillionuploadsCom"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Billionuploads.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "billionuploads.com"
diff --git a/module/plugins/accounts/BitshareCom.py b/module/plugins/accounts/BitshareCom.py
index 3802b2c46..960ff6c3c 100644
--- a/module/plugins/accounts/BitshareCom.py
+++ b/module/plugins/accounts/BitshareCom.py
@@ -1,46 +1,33 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.Account import Account
class BitshareCom(Account):
- __name__ = "BitshareCom"
+ __name__ = "BitshareCom"
+ __type__ = "account"
__version__ = "0.12"
- __type__ = "account"
__description__ = """Bitshare account plugin"""
- __author_name__ = "Paul King"
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = [("Paul King", None)]
def loadAccountInfo(self, user, req):
- page = req.load("http://bitshare.com/mysettings.html")
+ html = req.load("http://bitshare.com/mysettings.html")
- if "\"http://bitshare.com/myupgrade.html\">Free" in page:
+ if "\"http://bitshare.com/myupgrade.html\">Free" in html:
return {"validuntil": -1, "trafficleft": -1, "premium": False}
- if not '<input type="checkbox" name="directdownload" checked="checked" />' in page:
+ if not '<input type="checkbox" name="directdownload" checked="checked" />' in html:
self.logWarning(_("Activate direct Download in your Bitshare Account"))
return {"validuntil": -1, "trafficleft": -1, "premium": True}
+
def login(self, user, data, req):
- page = req.load("http://bitshare.com/login.html",
+ html = req.load("http://bitshare.com/login.html",
post={"user": user, "password": data['password'], "submit": "Login"}, cookies=True)
+
if "login" in req.lastEffectiveURL:
self.wrongPassword()
diff --git a/module/plugins/accounts/CatShareNet.py b/module/plugins/accounts/CatShareNet.py
new file mode 100644
index 000000000..c33219685
--- /dev/null
+++ b/module/plugins/accounts/CatShareNet.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from time import mktime, strptime
+
+from module.plugins.Account import Account
+
+
+class CatShareNet(Account):
+ __name__ = "CatShareNet"
+ __type__ = "account"
+ __version__ = "0.01"
+
+ __description__ = """CatShareNet account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("prOq", None)]
+
+
+ PREMIUM_PATTERN = r'class="nav-collapse collapse pull-right">[\s\w<>=-."/:]*\sz.</a></li>\s*<li><a href="/premium">.*\s*<span style="color: red">(.*?)</span>[\s\w<>/]*href="/logout"'
+ VALID_UNTIL_PATTERN = r'<div class="span6 pull-right">[\s\w<>=-":;]*<span style="font-size:13px;">.*?<strong>(.*?)</strong></span>'
+
+
+ def loadAccountInfo(self, user, req):
+ premium = False
+ validuntil = -1
+
+ html = req.load("http://catshare.net/", decode=True)
+
+ try:
+ m = re.search(self.PREMIUM_PATTERN, html)
+ if "Premium" in m.group(1):
+ premium = True
+ except:
+ pass
+
+ try:
+ m = re.search(self.VALID_UNTIL_PATTERN, html)
+ expiredate = m.group(1)
+ if "-" not in expiredate:
+ validuntil = mktime(strptime(expiredate, "%d.%m.%Y"))
+ except:
+ pass
+
+ return {'premium': premium, 'trafficleft': -1, 'validuntil': validuntil}
+
+
+ def login(self, user, data, req):
+ html = req.load("http://catshare.net/login",
+ post={'user_email': user,
+ 'user_password': data['password'],
+ 'remindPassword': 0,
+ 'user[submit]': "Login"})
+
+ if not '<a href="/logout">Wyloguj</a>' in html:
+ self.wrongPassword()
diff --git a/module/plugins/accounts/CloudzillaTo.py b/module/plugins/accounts/CloudzillaTo.py
new file mode 100644
index 000000000..f0676f42f
--- /dev/null
+++ b/module/plugins/accounts/CloudzillaTo.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.Account import Account
+
+
+class CloudzillaTo(Account):
+ __name__ = "CloudzillaTo"
+ __type__ = "account"
+ __version__ = "0.01"
+
+ __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"})
+
+ if "ERROR" in html:
+ self.wrongPassword()
diff --git a/module/plugins/accounts/CramitIn.py b/module/plugins/accounts/CramitIn.py
index 9d352c967..a9e2274a2 100644
--- a/module/plugins/accounts/CramitIn.py
+++ b/module/plugins/accounts/CramitIn.py
@@ -1,15 +1,16 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.XFSPAccount import XFSPAccount
+from module.plugins.internal.XFSAccount import XFSAccount
-class CramitIn(XFSPAccount):
- __name__ = "CramitIn"
- __version__ = "0.01"
- __type__ = "account"
+class CramitIn(XFSAccount):
+ __name__ = "CramitIn"
+ __type__ = "account"
+ __version__ = "0.03"
__description__ = """Cramit.in account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- MAIN_PAGE = "http://cramit.in/"
+
+ HOSTER_DOMAIN = "cramit.in"
diff --git a/module/plugins/accounts/CyberlockerCh.py b/module/plugins/accounts/CyberlockerCh.py
deleted file mode 100644
index 297808a6e..000000000
--- a/module/plugins/accounts/CyberlockerCh.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from module.plugins.internal.XFSPAccount import XFSPAccount
-from module.plugins.internal.SimpleHoster import parseHtmlForm
-
-
-class CyberlockerCh(XFSPAccount):
- __name__ = "CyberlockerCh"
- __version__ = "0.01"
- __type__ = "account"
-
- __description__ = """Cyberlocker.ch account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- MAIN_PAGE = "http://cyberlocker.ch/"
-
-
- def login(self, user, data, req):
- html = req.load(self.MAIN_PAGE + 'login.html', decode=True)
-
- action, inputs = parseHtmlForm('name="FL"', html)
- if not inputs:
- inputs = {"op": "login",
- "redirect": self.MAIN_PAGE}
-
- inputs.update({"login": user,
- "password": data['password']})
-
- # Without this a 403 Forbidden is returned
- req.http.lastURL = self.MAIN_PAGE + 'login.html'
- html = req.load(self.MAIN_PAGE, post=inputs, decode=True)
-
- if 'Incorrect Login or Password' in html or '>Error<' in html:
- self.wrongPassword()
diff --git a/module/plugins/accounts/CzshareCom.py b/module/plugins/accounts/CzshareCom.py
index 912b9328b..414883228 100644
--- a/module/plugins/accounts/CzshareCom.py
+++ b/module/plugins/accounts/CzshareCom.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from time import mktime, strptime
import re
@@ -22,15 +7,17 @@ from module.plugins.Account import Account
class CzshareCom(Account):
- __name__ = "CzshareCom"
- __version__ = "0.14"
- __type__ = "account"
+ __name__ = "CzshareCom"
+ __type__ = "account"
+ __version__ = "0.15"
__description__ = """Czshare.com account plugin, now Sdilej.cz"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
- CREDIT_LEFT_PATTERN = r'<tr class="active">\s*<td>([0-9 ,]+) (KiB|MiB|GiB)</td>\s*<td>([^<]*)</td>\s*</tr>'
+
+ CREDIT_LEFT_PATTERN = r'<tr class="active">\s*<td>([\d ,]+) (KiB|MiB|GiB)</td>\s*<td>([^<]*)</td>\s*</tr>'
def loadAccountInfo(self, user, req):
@@ -40,10 +27,10 @@ class CzshareCom(Account):
if m is None:
return {"validuntil": 0, "trafficleft": 0}
else:
- credits = float(m.group(1).replace(' ', '').replace(',', '.'))
- credits = credits * 1024 ** {'KiB': 0, 'MiB': 1, 'GiB': 2}[m.group(2)]
- validuntil = mktime(strptime(m.group(3), '%d.%m.%y %H:%M'))
- return {"validuntil": validuntil, "trafficleft": credits}
+ trafficleft = self.parseTraffic(m.group(1).replace(' ', '').replace(',', '.')) + m.group(2)]
+ validuntil = mktime(strptime(m.group(3), '%d.%m.%y %H:%M'))
+ return {"validuntil": validuntil, "trafficleft": trafficleft}
+
def login(self, user, data, req):
html = req.load('https://sdilej.cz/index.php', post={
diff --git a/module/plugins/accounts/DdlstorageCom.py b/module/plugins/accounts/DdlstorageCom.py
deleted file mode 100644
index 9d90f4dab..000000000
--- a/module/plugins/accounts/DdlstorageCom.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from hashlib import md5
-from time import mktime, strptime
-
-from module.plugins.internal.XFSPAccount import XFSPAccount
-from module.common.json_layer import json_loads
-from module.utils import parseFileSize
-
-# DDLStorage API Documentation:
-# http://www.ddlstorage.com/cgi-bin/api_req.cgi?req_type=doc
-
-
-class DdlstorageCom(XFSPAccount):
- __name__ = "DdlstorageCom"
- __version__ = "1.00"
- __type__ = "account"
-
- __description__ = """DDLStorage.com account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- MAIN_PAGE = "http://ddlstorage.com/"
-
-
- def loadAccountInfo(self, user, req):
- password = self.accounts[user]['password']
- api_data = req.load('http://www.ddlstorage.com/cgi-bin/api_req.cgi',
- post={'req_type': 'user_info',
- 'client_id': 53472,
- 'user_login': user,
- 'user_password': md5(password).hexdigest(),
- 'sign': md5('user_info%d%s%s%s' % (53472, user, md5(password).hexdigest(),
- '25JcpU2dPOKg8E2OEoRqMSRu068r0Cv3')).hexdigest()})
- api_data = api_data.replace('<pre>', '').replace('</pre>', '')
- self.logDebug('Account Info API data: ' + api_data)
- api_data = json_loads(api_data)
-
- if api_data['status'] != 'OK': # 'status' must be always OK for a working account
- return {"premium": False, "valid": False}
-
- if api_data['account_type'] == 'REGISTERED':
- premium = False
- validuntil = None
- else:
- premium = True
- validuntil = int(mktime(strptime(api_data['premium_expire'], "%Y-%m-%d %H:%M:%S")))
-
- if api_data['usr_bandwidth_available'] == 'UNLIMITED':
- trafficleft = -1
- else:
- trafficleft = parseFileSize(api_data['usr_bandwidth_available']) / 1024
-
- return {"premium": premium, "validuntil": validuntil, "trafficleft": trafficleft}
diff --git a/module/plugins/accounts/DebridItaliaCom.py b/module/plugins/accounts/DebridItaliaCom.py
index 1ee0d96c2..878153fbf 100644
--- a/module/plugins/accounts/DebridItaliaCom.py
+++ b/module/plugins/accounts/DebridItaliaCom.py
@@ -1,50 +1,44 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
-import time
+
+from time import mktime, strptime
from module.plugins.Account import Account
class DebridItaliaCom(Account):
- __name__ = "DebridItaliaCom"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "DebridItaliaCom"
+ __type__ = "account"
+ __version__ = "0.12"
__description__ = """Debriditalia.com account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
- WALID_UNTIL_PATTERN = r"Premium valid till: (?P<D>[^|]+) \|"
+ WALID_UNTIL_PATTERN = r'Premium valid till: (.+?) \|'
def loadAccountInfo(self, user, req):
- if 'Account premium not activated' in self.html:
- return {"premium": False, "validuntil": None, "trafficleft": None}
+ info = {"premium": False, "validuntil": None, "trafficleft": None}
+ html = req.load("http://debriditalia.com/")
+
+ if 'Account premium not activated' not in html:
+ m = re.search(self.WALID_UNTIL_PATTERN, html)
+ if m:
+ validuntil = mktime(strptime(m.group(1), "%d/%m/%Y %H:%M"))
+ info = {"premium": True, "validuntil": validuntil, "trafficleft": -1}
+ else:
+ self.logError(_("Unable to retrieve account information"))
+
+ return info
- m = re.search(self.WALID_UNTIL_PATTERN, self.html)
- if m:
- validuntil = int(time.mktime(time.strptime(m.group('D'), "%d/%m/%Y %H:%M")))
- return {"premium": True, "validuntil": validuntil, "trafficleft": -1}
- else:
- self.logError('Unable to retrieve account information - Plugin may be out of date')
def login(self, user, data, req):
- self.html = req.load("http://debriditalia.com/login.php",
- get={"u": user, "p": data['password']})
- if 'NO' in self.html:
+ html = req.load("http://debriditalia.com/login.php",
+ get={'u': user, 'p': data['password']})
+
+ if 'NO' in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/DepositfilesCom.py b/module/plugins/accounts/DepositfilesCom.py
index 2037f35c4..ec23f7a51 100644
--- a/module/plugins/accounts/DepositfilesCom.py
+++ b/module/plugins/accounts/DepositfilesCom.py
@@ -8,25 +8,28 @@ from module.plugins.Account import Account
class DepositfilesCom(Account):
- __name__ = "DepositfilesCom"
- __version__ = "0.3"
- __type__ = "account"
+ __name__ = "DepositfilesCom"
+ __type__ = "account"
+ __version__ = "0.31"
__description__ = """Depositfiles.com account plugin"""
- __author_name__ = ("mkaay", "stickell", "Walter Purcaro")
- __author_mail__ = ("mkaay@mkaay.de", "l.stickell@yahoo.it", "vuolter@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("mkaay", "mkaay@mkaay.de"),
+ ("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
def loadAccountInfo(self, user, req):
- src = req.load("https://dfiles.eu/de/gold/")
- validuntil = re.search(r"Sie haben Gold Zugang bis: <b>(.*?)</b></div>", src).group(1)
+ html = req.load("https://dfiles.eu/de/gold/")
+ validuntil = re.search(r"Sie haben Gold Zugang bis: <b>(.*?)</b></div>", html).group(1)
- validuntil = int(mktime(strptime(validuntil, "%Y-%m-%d %H:%M:%S")))
+ validuntil = mktime(strptime(validuntil, "%Y-%m-%d %H:%M:%S"))
return {"validuntil": validuntil, "trafficleft": -1}
+
def login(self, user, data, req):
- src = req.load("https://dfiles.eu/de/login.php", get={"return": "/de/gold/payment.php"},
- post={"login": user, "password": data['password']})
- if r'<div class="error_message">Sie haben eine falsche Benutzername-Passwort-Kombination verwendet.</div>' in src:
+ html = req.load("https://dfiles.eu/de/login.php", get={"return": "/de/gold/payment.php"},
+ post={"login": user, "password": data['password']})
+ if r'<div class="error_message">Sie haben eine falsche Benutzername-Passwort-Kombination verwendet.</div>' in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/EasybytezCom.py b/module/plugins/accounts/EasybytezCom.py
index 755a4dbff..93d3e2c19 100644
--- a/module/plugins/accounts/EasybytezCom.py
+++ b/module/plugins/accounts/EasybytezCom.py
@@ -1,76 +1,19 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from time import mktime, strptime, gmtime
-from module.plugins.Account import Account
-from module.plugins.internal.SimpleHoster import parseHtmlForm
-from module.utils import parseFileSize
+from module.plugins.internal.XFSAccount import XFSAccount
-class EasybytezCom(Account):
- __name__ = "EasybytezCom"
- __version__ = "0.04"
- __type__ = "account"
+class EasybytezCom(XFSAccount):
+ __name__ = "EasybytezCom"
+ __type__ = "account"
+ __version__ = "0.12"
__description__ = """EasyBytez.com account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
- VALID_UNTIL_PATTERN = r'Premium account expire:</TD><TD><b>([^<]+)</b>'
- TRAFFIC_LEFT_PATTERN = r'<TR><TD>Traffic available today:</TD><TD><b>(?P<S>[^<]+)</b>'
-
-
- def loadAccountInfo(self, user, req):
- html = req.load("http://www.easybytez.com/?op=my_account", decode=True)
-
- validuntil = trafficleft = None
- premium = False
-
- m = re.search(self.VALID_UNTIL_PATTERN, html)
- if m:
- try:
- self.logDebug("Expire date: " + m.group(1))
- validuntil = mktime(strptime(m.group(1), "%d %B %Y"))
- except Exception, e:
- self.logError(e)
- if validuntil > mktime(gmtime()):
- premium = True
- trafficleft = -1
- else:
- m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- if m:
- trafficleft = m.group(1)
- if "Unlimited" in trafficleft:
- trafficleft = -1
- else:
- trafficleft = parseFileSize(trafficleft) / 1024
-
- return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}
-
- def login(self, user, data, req):
- html = req.load('http://www.easybytez.com/login.html', decode=True)
- action, inputs = parseHtmlForm('name="FL"', html)
- inputs.update({"login": user,
- "password": data['password'],
- "redirect": "http://www.easybytez.com/"})
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("guidobelix", "guidobelix@hotmail.it")]
- html = req.load(action, post=inputs, decode=True)
- if 'Incorrect Login or Password' in html or '>Error<' in html:
- self.wrongPassword()
+ HOSTER_DOMAIN = "easybytez.com"
diff --git a/module/plugins/accounts/EgoFilesCom.py b/module/plugins/accounts/EgoFilesCom.py
deleted file mode 100644
index cd568456f..000000000
--- a/module/plugins/accounts/EgoFilesCom.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-import time
-
-from module.plugins.Account import Account
-from module.utils import parseFileSize
-
-
-class EgoFilesCom(Account):
- __name__ = "EgoFilesCom"
- __version__ = "0.2"
- __type__ = "account"
-
- __description__ = """Egofiles.com account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- PREMIUM_ACCOUNT_PATTERN = '<br/>\s*Premium: (?P<P>[^/]*) / Traffic left: (?P<T>[\d.]*) (?P<U>\w*)\s*\\n\s*<br/>'
-
-
- def loadAccountInfo(self, user, req):
- html = req.load("http://egofiles.com")
- if 'You are logged as a Free User' in html:
- return {"premium": False, "validuntil": None, "trafficleft": None}
-
- m = re.search(self.PREMIUM_ACCOUNT_PATTERN, html)
- if m:
- validuntil = int(time.mktime(time.strptime(m.group('P'), "%Y-%m-%d %H:%M:%S")))
- trafficleft = parseFileSize(m.group('T'), m.group('U')) / 1024
- return {"premium": True, "validuntil": validuntil, "trafficleft": trafficleft}
- else:
- self.logError('Unable to retrieve account information - Plugin may be out of date')
-
- def login(self, user, data, req):
- # Set English language
- req.load("https://egofiles.com/ajax/lang.php?lang=en", just_header=True)
-
- html = req.load("http://egofiles.com/ajax/register.php",
- post={"log": 1,
- "loginV": user,
- "passV": data['password']})
- if 'Login successful' not in html:
- self.wrongPassword()
diff --git a/module/plugins/accounts/EuroshareEu.py b/module/plugins/accounts/EuroshareEu.py
index f396f9bf2..c75f8ee33 100644
--- a/module/plugins/accounts/EuroshareEu.py
+++ b/module/plugins/accounts/EuroshareEu.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from time import mktime, strptime
import re
@@ -22,13 +7,13 @@ from module.plugins.Account import Account
class EuroshareEu(Account):
- __name__ = "EuroshareEu"
+ __name__ = "EuroshareEu"
+ __type__ = "account"
__version__ = "0.01"
- __type__ = "account"
__description__ = """Euroshare.eu account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
def loadAccountInfo(self, user, req):
@@ -44,8 +29,8 @@ class EuroshareEu(Account):
return {"validuntil": validuntil, "trafficleft": -1, "premium": premium}
- def login(self, user, data, req):
+ def login(self, user, data, req):
html = req.load('http://euroshare.eu/customer-zone/login/', post={
"trvale": "1",
"login": user,
diff --git a/module/plugins/accounts/FastixRu.py b/module/plugins/accounts/FastixRu.py
index 9e8d1f4fe..d33d611c9 100644
--- a/module/plugins/accounts/FastixRu.py
+++ b/module/plugins/accounts/FastixRu.py
@@ -5,32 +5,34 @@ from module.common.json_layer import json_loads
class FastixRu(Account):
- __name__ = "FastixRu"
+ __name__ = "FastixRu"
+ __type__ = "account"
__version__ = "0.02"
- __type__ = "account"
__description__ = """Fastix account plugin"""
- __author_name__ = "Massimo Rosamilia"
- __author_mail__ = "max@spiritix.eu"
+ __license__ = "GPLv3"
+ __authors__ = [("Massimo Rosamilia", "max@spiritix.eu")]
def loadAccountInfo(self, user, req):
data = self.getAccountData(user)
- page = req.load("http://fastix.ru/api_v2/?apikey=%s&sub=getaccountdetails" % (data['api']))
- page = json_loads(page)
- points = page['points']
- kb = float(points)
- kb = kb * 1024 ** 2 / 1000
+ html = json_loads(req.load("http://fastix.ru/api_v2/", get={'apikey': data['api'], 'sub': "getaccountdetails"}))
+
+ points = html['points']
+ kb = float(points) * 1024 ** 2 / 1000
+
if points > 0:
account_info = {"validuntil": -1, "trafficleft": kb}
else:
account_info = {"validuntil": None, "trafficleft": None, "premium": False}
return account_info
+
def login(self, user, data, req):
- page = req.load("http://fastix.ru/api_v2/?sub=get_apikey&email=%s&password=%s" % (user, data['password']))
- api = json_loads(page)
+ html = req.load("http://fastix.ru/api_v2/",
+ get={'sub': "get_apikey", 'email': user, 'password': data['password']})
+ api = json_loads(html)
api = api['apikey']
data['api'] = api
- if "error_code" in page:
+ if "error_code" in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/FastshareCz.py b/module/plugins/accounts/FastshareCz.py
index 2ac24cf39..d6e94f2e3 100644
--- a/module/plugins/accounts/FastshareCz.py
+++ b/module/plugins/accounts/FastshareCz.py
@@ -1,56 +1,52 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.Account import Account
-from module.utils import parseFileSize
class FastshareCz(Account):
- __name__ = "FastshareCz"
- __version__ = "0.03"
- __type__ = "account"
+ __name__ = "FastshareCz"
+ __type__ = "account"
+ __version__ = "0.05"
__description__ = """Fastshare.cz account plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
- CREDIT_PATTERN = r'(?:Kredit|Credit)\s*</td>\s*<td[^>]*>([\d. \w]+)&nbsp;'
+ CREDIT_PATTERN = r'My account\s*\((.+?)\)'
def loadAccountInfo(self, user, req):
+ validuntil = None
+ trafficleft = None
+ premium = None
+
html = req.load("http://www.fastshare.cz/user", decode=True)
m = re.search(self.CREDIT_PATTERN, html)
if m:
- trafficleft = parseFileSize(m.group(1)) / 1024
- premium = True if trafficleft else False
+ trafficleft = self.parseTraffic(m.group(1))
+
+ if trafficleft:
+ premium = True
+ validuntil = -1
else:
- trafficleft = None
premium = False
- return {"validuntil": -1, "trafficleft": trafficleft, "premium": premium}
+ return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}
+
def login(self, user, data, req):
+ req.cj.setCookie("fastshare.cz", "lang", "en")
+
req.load('http://www.fastshare.cz/login') # Do not remove or it will not login
- html = req.load('http://www.fastshare.cz/sql.php', post={
- "heslo": data['password'],
- "login": user
- }, decode=True)
- if u'>Špatné uşivatelské jméno nebo heslo.<' in html:
+ html = req.load("http://www.fastshare.cz/sql.php",
+ post={'login': user, 'heslo': data['password']},
+ decode=True)
+
+ if ">Wrong username or password" in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/File4safeCom.py b/module/plugins/accounts/File4safeCom.py
index 158d7be3b..20053d895 100644
--- a/module/plugins/accounts/File4safeCom.py
+++ b/module/plugins/accounts/File4safeCom.py
@@ -1,18 +1,18 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.XFSPAccount import XFSPAccount
+from module.plugins.internal.XFSAccount import XFSAccount
-class File4safeCom(XFSPAccount):
- __name__ = "File4safeCom"
- __version__ = "0.01"
- __type__ = "account"
+class File4safeCom(XFSAccount):
+ __name__ = "File4safeCom"
+ __type__ = "account"
+ __version__ = "0.04"
__description__ = """File4safe.com account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
- MAIN_PAGE = "http://file4safe.com/"
+
+ HOSTER_DOMAIN = "file4safe.com"
LOGIN_FAIL_PATTERN = r'input_login'
- PREMIUM_PATTERN = r'Extend Premium'
diff --git a/module/plugins/accounts/FileParadoxIn.py b/module/plugins/accounts/FileParadoxIn.py
new file mode 100644
index 000000000..c12d99d6a
--- /dev/null
+++ b/module/plugins/accounts/FileParadoxIn.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class FileParadoxIn(XFSAccount):
+ __name__ = "FileParadoxIn"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """FileParadox.in account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "fileparadox.in"
diff --git a/module/plugins/accounts/FilecloudIo.py b/module/plugins/accounts/FilecloudIo.py
index b8bad5c4c..d20f756f3 100644
--- a/module/plugins/accounts/FilecloudIo.py
+++ b/module/plugins/accounts/FilecloudIo.py
@@ -1,44 +1,30 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.Account import Account
from module.common.json_layer import json_loads
class FilecloudIo(Account):
- __name__ = "FilecloudIo"
- __version__ = "0.02"
- __type__ = "account"
+ __name__ = "FilecloudIo"
+ __type__ = "account"
+ __version__ = "0.03"
__description__ = """FilecloudIo account plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
def loadAccountInfo(self, user, req):
# It looks like the first API request always fails, so we retry 5 times, it should work on the second try
- for _ in xrange(5):
+ for _i in xrange(5):
rep = req.load("https://secure.filecloud.io/api-fetch_apikey.api",
post={"username": user, "password": self.accounts[user]['password']})
rep = json_loads(rep)
if rep['status'] == 'ok':
break
elif rep['status'] == 'error' and rep['message'] == 'no such user or wrong password':
- self.logError("Wrong username or password")
+ self.logError(_("Wrong username or password"))
return {"valid": False, "premium": False}
else:
return {"premium": False}
@@ -50,10 +36,11 @@ class FilecloudIo(Account):
rep = json_loads(rep)
if rep['is_premium'] == 1:
- return {"validuntil": int(rep['premium_until']), "trafficleft": -1}
+ return {"validuntil": float(rep['premium_until']), "trafficleft": -1}
else:
return {"premium": False}
+
def login(self, user, data, req):
req.cj.setCookie("secure.filecloud.io", "lang", "en")
html = req.load('https://secure.filecloud.io/user-login.html')
diff --git a/module/plugins/accounts/FilefactoryCom.py b/module/plugins/accounts/FilefactoryCom.py
index be96d8a52..8394c549e 100644
--- a/module/plugins/accounts/FilefactoryCom.py
+++ b/module/plugins/accounts/FilefactoryCom.py
@@ -1,18 +1,4 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
from time import mktime, strptime
@@ -23,15 +9,17 @@ from module.plugins.Account import Account
class FilefactoryCom(Account):
- __name__ = "FilefactoryCom"
+ __name__ = "FilefactoryCom"
+ __type__ = "account"
__version__ = "0.14"
- __type__ = "account"
__description__ = """Filefactory.com account plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
- VALID_UNTIL_PATTERN = r'Premium valid until: <strong>(?P<d>\d{1,2})\w{1,2} (?P<m>\w{3}), (?P<y>\d{4})</strong>'
+
+ VALID_UNTIL_PATTERN = r'Premium valid until: <strong>(?P<D>\d{1,2})\w{1,2} (?P<M>\w{3}), (?P<Y>\d{4})</strong>'
def loadAccountInfo(self, user, req):
@@ -40,7 +28,7 @@ class FilefactoryCom(Account):
m = re.search(self.VALID_UNTIL_PATTERN, html)
if m:
premium = True
- validuntil = re.sub(self.VALID_UNTIL_PATTERN, '\g<d> \g<m> \g<y>', m.group(0))
+ validuntil = re.sub(self.VALID_UNTIL_PATTERN, '\g<D> \g<M> \g<Y>', m.group(0))
validuntil = mktime(strptime(validuntil, "%d %b %Y"))
else:
premium = False
@@ -48,6 +36,7 @@ class FilefactoryCom(Account):
return {"premium": premium, "trafficleft": -1, "validuntil": validuntil}
+
def login(self, user, data, req):
req.http.c.setopt(REFERER, "http://www.filefactory.com/member/login.php")
diff --git a/module/plugins/accounts/FilejungleCom.py b/module/plugins/accounts/FilejungleCom.py
index 7c894e3d6..a3ec7af64 100644
--- a/module/plugins/accounts/FilejungleCom.py
+++ b/module/plugins/accounts/FilejungleCom.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from time import mktime, strptime
@@ -22,18 +7,19 @@ from module.plugins.Account import Account
class FilejungleCom(Account):
- __name__ = "FilejungleCom"
+ __name__ = "FilejungleCom"
+ __type__ = "account"
__version__ = "0.11"
- __type__ = "account"
__description__ = """Filejungle.com account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
login_timeout = 60
URL = "http://filejungle.com/"
- TRAFFIC_LEFT_PATTERN = r'"/extend_premium\.php">Until (\d+ [A-Za-z]+ \d+)<br'
+ TRAFFIC_LEFT_PATTERN = r'"/extend_premium\.php">Until (\d+ \w+ \d+)<br'
LOGIN_FAILED_PATTERN = r'<span htmlfor="loginUser(Name|Password)" generated="true" class="fail_info">'
@@ -49,6 +35,7 @@ class FilejungleCom(Account):
return {"premium": premium, "trafficleft": -1, "validuntil": validuntil}
+
def login(self, user, data, req):
html = req.load(self.URL + "login.php", post={
"loginUserName": user,
diff --git a/module/plugins/accounts/FileomCom.py b/module/plugins/accounts/FileomCom.py
new file mode 100644
index 000000000..7c743f56a
--- /dev/null
+++ b/module/plugins/accounts/FileomCom.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class FileomCom(XFSAccount):
+ __name__ = "FileomCom"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Fileom.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "fileom.com"
diff --git a/module/plugins/accounts/FilerNet.py b/module/plugins/accounts/FilerNet.py
index 0eaa8f452..a845e7ba4 100644
--- a/module/plugins/accounts/FilerNet.py
+++ b/module/plugins/accounts/FilerNet.py
@@ -1,37 +1,23 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
import time
from module.plugins.Account import Account
-from module.utils import parseFileSize
class FilerNet(Account):
- __name__ = "FilerNet"
- __version__ = "0.01"
- __type__ = "account"
+ __name__ = "FilerNet"
+ __type__ = "account"
+ __version__ = "0.03"
__description__ = """Filer.net account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
TOKEN_PATTERN = r'_csrf_token" value="([^"]+)" />'
- WALID_UNTIL_PATTERN = r"Der Premium-Zugang ist gÃŒltig bis (.+)\.\s*</td>"
+ WALID_UNTIL_PATTERN = r'Der Premium-Zugang ist gÃŒltig bis (.+)\.\s*</td>'
TRAFFIC_PATTERN = r'Traffic</th>\s*<td>([^<]+)</td>'
FREE_PATTERN = r'Account Status</th>\s*<td>\s*Free'
@@ -43,16 +29,19 @@ class FilerNet(Account):
if re.search(self.FREE_PATTERN, html):
return {"premium": False, "validuntil": None, "trafficleft": None}
- until = re.search(self.WALID_UNTIL_PATTERN, html)
+ until = re.search(self.WALID_UNTIL_PATTERN, html)
traffic = re.search(self.TRAFFIC_PATTERN, html)
+
if until and traffic:
- validuntil = int(time.mktime(time.strptime(until.group(1), "%d.%m.%Y %H:%M:%S")))
- trafficleft = parseFileSize(traffic.group(1)) / 1024
+ validuntil = time.mktime(time.strptime(until.group(1), "%d.%m.%Y %H:%M:%S"))
+ trafficleft = self.parseTraffic(traffic.group(1))
return {"premium": True, "validuntil": validuntil, "trafficleft": trafficleft}
+
else:
- self.logError('Unable to retrieve account information - Plugin may be out of date')
+ self.logError(_("Unable to retrieve account information"))
return {"premium": False, "validuntil": None, "trafficleft": None}
+
def login(self, user, data, req):
html = req.load("https://filer.net/login")
token = re.search(self.TOKEN_PATTERN, html).group(1)
diff --git a/module/plugins/accounts/FilerioCom.py b/module/plugins/accounts/FilerioCom.py
index 7288930f4..4c6755293 100644
--- a/module/plugins/accounts/FilerioCom.py
+++ b/module/plugins/accounts/FilerioCom.py
@@ -1,15 +1,16 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.XFSPAccount import XFSPAccount
+from module.plugins.internal.XFSAccount import XFSAccount
-class FilerioCom(XFSPAccount):
- __name__ = "FilerioCom"
- __version__ = "0.01"
- __type__ = "account"
+class FilerioCom(XFSAccount):
+ __name__ = "FilerioCom"
+ __type__ = "account"
+ __version__ = "0.03"
__description__ = """FileRio.in account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- MAIN_PAGE = "http://filerio.in/"
+
+ HOSTER_DOMAIN = "filerio.in"
diff --git a/module/plugins/accounts/FilesMailRu.py b/module/plugins/accounts/FilesMailRu.py
index a87aac8a8..f91f4d5ba 100644
--- a/module/plugins/accounts/FilesMailRu.py
+++ b/module/plugins/accounts/FilesMailRu.py
@@ -1,42 +1,28 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.Account import Account
class FilesMailRu(Account):
- __name__ = "FilesMailRu"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "FilesMailRu"
+ __type__ = "account"
+ __version__ = "0.10"
__description__ = """Filesmail.ru account plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
def loadAccountInfo(self, user, req):
return {"validuntil": None, "trafficleft": None}
+
def login(self, user, data, req):
user, domain = user.split("@")
- page = req.load("http://swa.mail.ru/cgi-bin/auth", None,
+ html = req.load("http://swa.mail.ru/cgi-bin/auth", None,
{"Domain": domain, "Login": user, "Password": data['password'],
"Page": "http://files.mail.ru/"}, cookies=True)
- if "НеверМПе ОЌя пПльзПвателя ОлО парПль" in page: # @TODO seems not to work
+ if "НеверМПе ОЌя пПльзПвателя ОлО парПль" in html: # @TODO seems not to work
self.wrongPassword()
diff --git a/module/plugins/accounts/FileserveCom.py b/module/plugins/accounts/FileserveCom.py
index f91f5b703..1cf2a3a3c 100644
--- a/module/plugins/accounts/FileserveCom.py
+++ b/module/plugins/accounts/FileserveCom.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from time import mktime, strptime
from module.plugins.Account import Account
@@ -22,21 +7,21 @@ from module.common.json_layer import json_loads
class FileserveCom(Account):
- __name__ = "FileserveCom"
- __version__ = "0.2"
- __type__ = "account"
+ __name__ = "FileserveCom"
+ __type__ = "account"
+ __version__ = "0.20"
__description__ = """Fileserve.com account plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __license__ = "GPLv3"
+ __authors__ = [("mkaay", "mkaay@mkaay.de")]
def loadAccountInfo(self, user, req):
data = self.getAccountData(user)
- page = req.load("http://app.fileserve.com/api/login/", post={"username": user, "password": data['password'],
+ html = req.load("http://app.fileserve.com/api/login/", post={"username": user, "password": data['password'],
"submit": "Submit+Query"})
- res = json_loads(page)
+ res = json_loads(html)
if res['type'] == "premium":
validuntil = mktime(strptime(res['expireTime'], "%Y-%m-%d %H:%M:%S"))
@@ -44,15 +29,16 @@ class FileserveCom(Account):
else:
return {"premium": False, "trafficleft": None, "validuntil": None}
+
def login(self, user, data, req):
- page = req.load("http://app.fileserve.com/api/login/", post={"username": user, "password": data['password'],
+ html = req.load("http://app.fileserve.com/api/login/", post={"username": user, "password": data['password'],
"submit": "Submit+Query"})
- res = json_loads(page)
+ res = json_loads(html)
if not res['type']:
self.wrongPassword()
- #login at fileserv page
+ #login at fileserv html
req.load("http://www.fileserve.com/login.php",
post={"loginUserName": user, "loginUserPassword": data['password'], "autoLogin": "checked",
"loginFormSubmit": "Login"})
diff --git a/module/plugins/accounts/FourSharedCom.py b/module/plugins/accounts/FourSharedCom.py
index b8a0c33f6..ec19f83f5 100644
--- a/module/plugins/accounts/FourSharedCom.py
+++ b/module/plugins/accounts/FourSharedCom.py
@@ -1,49 +1,33 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-from module.plugins.Account import Account
from module.common.json_layer import json_loads
+from module.plugins.Account import Account
class FourSharedCom(Account):
- __name__ = "FourSharedCom"
- __version__ = "0.01"
- __type__ = "account"
+ __name__ = "FourSharedCom"
+ __type__ = "account"
+ __version__ = "0.03"
__description__ = """FourShared.com account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
def loadAccountInfo(self, user, req):
- #fixme
- return {"validuntil": -1, "trafficleft": -1, "premium": False}
+ # Free mode only for now
+ return {"premium": False}
+
def login(self, user, data, req):
- req.cj.setCookie("www.4shared.com", "4langcookie", "en")
- response = req.load('http://www.4shared.com/login',
- post={"login": user,
- "password": data['password'],
- "remember": "false",
- "doNotRedirect": "true"})
- self.logDebug(response)
- response = json_loads(response)
-
- if not "ok" in response or response['ok'] != True:
- if "rejectReason" in response and response['rejectReason'] != True:
- self.logError(response['rejectReason'])
+ req.cj.setCookie("4shared.com", "4langcookie", "en")
+ res = req.load('http://www.4shared.com/web/login',
+ post={'login': user,
+ 'password': data['password'],
+ 'remember': "on",
+ '_remember': "on",
+ 'returnTo': "http://www.4shared.com/account/home.jsp"})
+
+ if 'Please log in to access your 4shared account' in res:
self.wrongPassword()
diff --git a/module/plugins/accounts/FreakshareCom.py b/module/plugins/accounts/FreakshareCom.py
index 2987b21eb..576d835e2 100644
--- a/module/plugins/accounts/FreakshareCom.py
+++ b/module/plugins/accounts/FreakshareCom.py
@@ -1,53 +1,51 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
import re
+
from time import strptime, mktime
from module.plugins.Account import Account
class FreakshareCom(Account):
- __name__ = "FreakshareCom"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "FreakshareCom"
+ __type__ = "account"
+ __version__ = "0.12"
__description__ = """Freakshare.com account plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
def loadAccountInfo(self, user, req):
- page = req.load("http://freakshare.com/")
+ premium = False
+ validuntil = None
+ trafficleft = None
+
+ html = req.load("http://freakshare.com/")
+
+ try:
+ m = re.search(r'ltig bis:</td>\s*<td><b>([\d.:-]+)</b></td>', html, re.M)
+ validuntil = mktime(strptime(m.group(1).strip(), "%d.%m.%Y - %H:%M"))
- validuntil = r"ltig bis:</td>\s*<td><b>([0-9 \-:.]+)</b></td>"
- validuntil = re.search(validuntil, page, re.MULTILINE)
- validuntil = validuntil.group(1).strip()
- validuntil = mktime(strptime(validuntil, "%d.%m.%Y - %H:%M"))
+ except Exception:
+ pass
- traffic = r"Traffic verbleibend:</td>\s*<td>([^<]+)"
- traffic = re.search(traffic, page, re.MULTILINE)
- traffic = traffic.group(1).strip()
- traffic = self.parseTraffic(traffic)
+ try:
+ m = re.search(r'Traffic verbleibend:</td>\s*<td>([^<]+)', html, re.M)
+ trafficleft = self.parseTraffic(m.group(1))
+
+ except Exception:
+ pass
+
+ return {"premium": premium, "validuntil": validuntil, "trafficleft": trafficleft}
- return {"validuntil": validuntil, "trafficleft": traffic}
def login(self, user, data, req):
- page = req.load("http://freakshare.com/login.html", None,
+ req.load("http://freakshare.com/index.php?language=EN")
+
+ html = req.load("http://freakshare.com/login.html", None,
{"submit": "Login", "user": user, "pass": data['password']}, cookies=True)
- if "Falsche Logindaten!" in page or "Wrong Username or Password!" in page:
+ if ">Wrong Username or Password" in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/FreeWayMe.py b/module/plugins/accounts/FreeWayMe.py
index 8a7d46aa1..3b9841630 100644
--- a/module/plugins/accounts/FreeWayMe.py
+++ b/module/plugins/accounts/FreeWayMe.py
@@ -1,32 +1,17 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.Account import Account
from module.common.json_layer import json_loads
class FreeWayMe(Account):
- __name__ = "FreeWayMe"
- __version__ = "0.11"
- __type__ = "account"
+ __name__ = "FreeWayMe"
+ __type__ = "account"
+ __version__ = "0.12"
__description__ = """FreeWayMe account plugin"""
- __author_name__ = "Nicolas Giese"
- __author_mail__ = "james@free-way.me"
+ __license__ = "GPLv3"
+ __authors__ = [("Nicolas Giese", "james@free-way.me")]
def loadAccountInfo(self, user, req):
@@ -37,19 +22,21 @@ class FreeWayMe(Account):
account_info = {"validuntil": -1, "premium": False}
if status['premium'] == "Free":
- account_info['trafficleft'] = int(status['guthaben']) * 1024
+ account_info['trafficleft'] = self.parseTraffic(status['guthaben'] + "MB")
elif status['premium'] == "Spender":
account_info['trafficleft'] = -1
elif status['premium'] == "Flatrate":
- account_info = {"validuntil": int(status['Flatrate']),
+ account_info = {"validuntil": float(status['Flatrate']),
"trafficleft": -1,
"premium": True}
return account_info
+
def getpw(self, user):
return self.accounts[user]['password']
+
def login(self, user, data, req):
status = self.getAccountStatus(user, req)
@@ -57,10 +44,11 @@ class FreeWayMe(Account):
if not status:
self.wrongPassword()
+
def getAccountStatus(self, user, req):
answer = req.load("https://www.free-way.me/ajax/jd.php",
get={"id": 4, "user": user, "pass": self.accounts[user]['password']})
- self.logDebug("login: %s" % answer)
+ self.logDebug("Login: %s" % answer)
if answer == "Invalid login":
self.wrongPassword()
return False
diff --git a/module/plugins/accounts/FshareVn.py b/module/plugins/accounts/FshareVn.py
index 5726ad410..2da45aac6 100644
--- a/module/plugins/accounts/FshareVn.py
+++ b/module/plugins/accounts/FshareVn.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from time import mktime, strptime
from pycurl import REFERER
import re
@@ -23,17 +8,19 @@ from module.plugins.Account import Account
class FshareVn(Account):
- __name__ = "FshareVn"
- __version__ = "0.07"
- __type__ = "account"
+ __name__ = "FshareVn"
+ __type__ = "account"
+ __version__ = "0.08"
__description__ = """Fshare.vn account plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
VALID_UNTIL_PATTERN = ur'<dt>Thời hạn dùng:</dt>\s*<dd>([^<]+)</dd>'
LIFETIME_PATTERN = ur'<dt>Lần đăng nhập trước:</dt>\s*<dd>[^<]+</dd>'
- TRAFFIC_LEFT_PATTERN = ur'<dt>Tổng Dung Lượng Tài Khoản</dt>\s*<dd[^>]*>([0-9.]+) ([kKMG])B</dd>'
+ TRAFFIC_LEFT_PATTERN = ur'<dt>Tổng Dung Lượng Tài Khoản</dt>\s*<dd[^>]*>([\d.]+) ([kKMG])B</dd>'
DIRECT_DOWNLOAD_PATTERN = ur'<input type="checkbox"\s*([^=>]*)[^>]*/>Kích hoạt download trực tiếp</dt>'
@@ -57,6 +44,7 @@ class FshareVn(Account):
return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}
+
def login(self, user, data, req):
req.http.c.setopt(REFERER, "https://www.fshare.vn/login.php")
@@ -69,6 +57,7 @@ class FshareVn(Account):
if not re.search(r'<img\s+alt="VIP"', html):
self.wrongPassword()
+
def getTrafficLeft(self):
m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- return float(m.group(1)) * 1024 ** {'k': 0, 'K': 0, 'M': 1, 'G': 2}[m.group(2)] if m else 0
+ return self.parseTraffic(m.group(1) + m.group(2)) if m else 0
diff --git a/module/plugins/accounts/Ftp.py b/module/plugins/accounts/Ftp.py
index 93f161bb9..f978d2fa0 100644
--- a/module/plugins/accounts/Ftp.py
+++ b/module/plugins/accounts/Ftp.py
@@ -4,13 +4,14 @@ from module.plugins.Account import Account
class Ftp(Account):
- __name__ = "Ftp"
+ __name__ = "Ftp"
+ __type__ = "account"
__version__ = "0.01"
- __type__ = "account"
__description__ = """Ftp dummy account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- login_timeout = info_threshold = 1000000
+ info_threshold = 1000000
+ login_timeout = 1000000
diff --git a/module/plugins/accounts/HellshareCz.py b/module/plugins/accounts/HellshareCz.py
index d6e65a33e..dff2fe394 100644
--- a/module/plugins/accounts/HellshareCz.py
+++ b/module/plugins/accounts/HellshareCz.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
import time
@@ -22,13 +7,14 @@ from module.plugins.Account import Account
class HellshareCz(Account):
- __name__ = "HellshareCz"
- __version__ = "0.14"
- __type__ = "account"
+ __name__ = "HellshareCz"
+ __type__ = "account"
+ __version__ = "0.15"
__description__ = """Hellshare.cz account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
CREDIT_LEFT_PATTERN = r'<div class="credit-link">\s*<table>\s*<tr>\s*<th>(\d+|\d\d\.\d\d\.)</th>'
@@ -55,27 +41,28 @@ class HellshareCz(Account):
trafficleft = -1
else:
#Traffic-based account
- trafficleft = int(credit) * 1024
+ trafficleft = self.parseTraffic(credit + "MB")
validuntil = -1
except Exception, e:
- self.logError('Unable to parse credit info', e)
+ self.logError(_("Unable to parse credit info"), e)
validuntil = -1
trafficleft = -1
return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}
+
def login(self, user, data, req):
html = req.load('http://www.hellshare.com/')
if req.lastEffectiveURL != 'http://www.hellshare.com/':
#Switch to English
- self.logDebug('Switch lang - URL: %s' % req.lastEffectiveURL)
+ self.logDebug("Switch lang - URL: %s" % req.lastEffectiveURL)
json = req.load("%s?do=locRouter-show" % req.lastEffectiveURL)
- hash = re.search(r"(--[0-9a-f]+-)", json).group(1)
- self.logDebug('Switch lang - HASH: %s' % hash)
+ hash = re.search(r"(\-\-[0-9a-f]+\-)", json).group(1)
+ self.logDebug("Switch lang - HASH: %s" % hash)
html = req.load('http://www.hellshare.com/%s/' % hash)
if re.search(self.CREDIT_LEFT_PATTERN, html):
- self.logDebug('Already logged in')
+ self.logDebug("Already logged in")
return
html = req.load('http://www.hellshare.com/login?do=loginForm-submit', post={
diff --git a/module/plugins/accounts/HotfileCom.py b/module/plugins/accounts/HotfileCom.py
deleted file mode 100644
index 515517be4..000000000
--- a/module/plugins/accounts/HotfileCom.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-from time import strptime, mktime
-import hashlib
-
-from module.plugins.Account import Account
-
-
-class HotfileCom(Account):
- __name__ = "HotfileCom"
- __version__ = "0.2"
- __type__ = "account"
-
- __description__ = """Hotfile.com account plugin"""
- __author_name__ = ("mkaay", "JoKoT3")
- __author_mail__ = ("mkaay@mkaay.de", "jokot3@gmail.com")
-
-
- def loadAccountInfo(self, user, req):
- resp = self.apiCall("getuserinfo", user=user)
- if resp.startswith("."):
- self.core.debug("HotfileCom API Error: %s" % resp)
- raise Exception
- info = {}
- for p in resp.split("&"):
- key, value = p.split("=")
- info[key] = value
-
- if info['is_premium'] == '1':
- info['premium_until'] = info['premium_until'].replace("T", " ")
- zone = info['premium_until'][19:]
- info['premium_until'] = info['premium_until'][:19]
- zone = int(zone[:3])
-
- validuntil = int(mktime(strptime(info['premium_until'], "%Y-%m-%d %H:%M:%S"))) + (zone * 60 * 60)
- tmp = {"validuntil": validuntil, "trafficleft": -1, "premium": True}
-
- elif info['is_premium'] == '0':
- tmp = {"premium": False}
-
- return tmp
-
- def apiCall(self, method, post={}, user=None):
- if user:
- data = self.getAccountData(user)
- else:
- user, data = self.selectAccount()
-
- req = self.getAccountRequest(user)
-
- digest = req.load("http://api.hotfile.com/", post={"action": "getdigest"})
- h = hashlib.md5()
- h.update(data['password'])
- hp = h.hexdigest()
- h = hashlib.md5()
- h.update(hp)
- h.update(digest)
- pwhash = h.hexdigest()
-
- post.update({"action": method})
- post.update({"username": user, "passwordmd5dig": pwhash, "digest": digest})
- resp = req.load("http://api.hotfile.com/", post=post)
- req.close()
- return resp
-
- def login(self, user, data, req):
- cj = self.getAccountCookies(user)
- cj.setCookie("hotfile.com", "lang", "en")
- req.load("http://hotfile.com/", cookies=True)
- page = req.load("http://hotfile.com/login.php", post={"returnto": "/", "user": user, "pass": data['password']},
- cookies=True)
-
- if "Bad username/password" in page:
- self.wrongPassword()
diff --git a/module/plugins/accounts/Http.py b/module/plugins/accounts/Http.py
index b79a78c99..07e46eb07 100644
--- a/module/plugins/accounts/Http.py
+++ b/module/plugins/accounts/Http.py
@@ -4,13 +4,14 @@ from module.plugins.Account import Account
class Http(Account):
- __name__ = "Http"
+ __name__ = "Http"
+ __type__ = "account"
__version__ = "0.01"
- __type__ = "account"
__description__ = """Http dummy account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- login_timeout = info_threshold = 1000000
+ info_threshold = 1000000
+ login_timeout = 1000000
diff --git a/module/plugins/accounts/HugefilesNet.py b/module/plugins/accounts/HugefilesNet.py
new file mode 100644
index 000000000..5da3bbc37
--- /dev/null
+++ b/module/plugins/accounts/HugefilesNet.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class HugefilesNet(XFSAccount):
+ __name__ = "HugefilesNet"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Hugefiles.net account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "hugefiles.net"
diff --git a/module/plugins/accounts/HundredEightyUploadCom.py b/module/plugins/accounts/HundredEightyUploadCom.py
new file mode 100644
index 000000000..39f91a8af
--- /dev/null
+++ b/module/plugins/accounts/HundredEightyUploadCom.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class HundredEightyUploadCom(XFSAccount):
+ __name__ = "HundredEightyUploadCom"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """180upload.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "180upload.com"
diff --git a/module/plugins/accounts/JunocloudMe.py b/module/plugins/accounts/JunocloudMe.py
new file mode 100644
index 000000000..b0fc160f3
--- /dev/null
+++ b/module/plugins/accounts/JunocloudMe.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class JunocloudMe(XFSAccount):
+ __name__ = "JunocloudMe"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Junocloud.me account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("guidobelix", "guidobelix@hotmail.it")]
+
+
+ HOSTER_DOMAIN = "junocloud.me"
diff --git a/module/plugins/accounts/Keep2shareCc.py b/module/plugins/accounts/Keep2shareCc.py
new file mode 100644
index 000000000..fac3cc4a6
--- /dev/null
+++ b/module/plugins/accounts/Keep2shareCc.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from time import gmtime, mktime, strptime
+
+from module.plugins.Account import Account
+
+
+class Keep2shareCc(Account):
+ __name__ = "Keep2shareCc"
+ __type__ = "account"
+ __version__ = "0.03"
+
+ __description__ = """Keep2share.cc account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("aeronaut", "aeronaut@pianoguy.de")]
+
+
+ VALID_UNTIL_PATTERN = r'Premium expires: <b>(.+?)</b>'
+ TRAFFIC_LEFT_PATTERN = r'Available traffic \(today\):\s*<b><a href="/user/statistic.html">(.+?)<'
+
+ LOGIN_FAIL_PATTERN = r'Please fix the following input errors'
+
+
+ def loadAccountInfo(self, user, req):
+ validuntil = None
+ trafficleft = None
+ premium = None
+
+ html = req.load("http://keep2share.cc/site/profile.html", decode=True)
+
+ m = re.search(self.VALID_UNTIL_PATTERN, html)
+ if m:
+ expiredate = m.group(1).strip()
+ self.logDebug("Expire date: " + expiredate)
+
+ try:
+ validuntil = mktime(strptime(expiredate, "%Y.%m.%d"))
+
+ except Exception, e:
+ self.logError(e)
+
+ else:
+ if validuntil > mktime(gmtime()):
+ premium = True
+ else:
+ premium = False
+ validuntil = None
+
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+ if m:
+ try:
+ trafficleft = self.parseTraffic(m.group(1))
+
+ except Exception, e:
+ self.logError(e)
+
+ return {'validuntil': validuntil, 'trafficleft': trafficleft, 'premium': premium}
+
+
+ def login(self, user, data, req):
+ req.cj.setCookie("keep2share.cc", "lang", "en")
+
+ html = req.load("http://keep2share.cc/login.html",
+ post={'LoginForm[username]' : user,
+ 'LoginForm[password]' : data['password'],
+ 'LoginForm[rememberMe]': 1,
+ 'yt0' : ""})
+
+ if re.search(self.LOGIN_FAIL_PATTERN, html):
+ self.wrongPassword()
diff --git a/module/plugins/accounts/LetitbitNet.py b/module/plugins/accounts/LetitbitNet.py
index 3bd096d55..b8244a06d 100644
--- a/module/plugins/accounts/LetitbitNet.py
+++ b/module/plugins/accounts/LetitbitNet.py
@@ -1,31 +1,17 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
from module.plugins.Account import Account
# from module.common.json_layer import json_loads, json_dumps
class LetitbitNet(Account):
- __name__ = "LetitbitNet"
+ __name__ = "LetitbitNet"
+ __type__ = "account"
__version__ = "0.01"
- __type__ = "account"
__description__ = """Letitbit.net account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
def loadAccountInfo(self, user, req):
@@ -33,7 +19,7 @@ class LetitbitNet(Account):
# api_key = self.accounts[user]['password']
# json_data = [api_key, ['key/info']]
# api_rep = req.load('http://api.letitbit.net/json', post={'r': json_dumps(json_data)})
- # self.logDebug('API Key Info: ' + api_rep)
+ # self.logDebug("API Key Info: " + api_rep)
# api_rep = json_loads(api_rep)
#
# if api_rep['status'] == 'FAIL':
@@ -42,6 +28,7 @@ class LetitbitNet(Account):
return {"premium": True}
+
def login(self, user, data, req):
# API_KEY is the username and the PREMIUM_KEY is the password
- self.logInfo('You must use your API KEY as username and the PREMIUM KEY as password.')
+ self.logInfo(_("You must use your API KEY as username and the PREMIUM KEY as password"))
diff --git a/module/plugins/accounts/LinestorageCom.py b/module/plugins/accounts/LinestorageCom.py
new file mode 100644
index 000000000..a48d5beb9
--- /dev/null
+++ b/module/plugins/accounts/LinestorageCom.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class LinestorageCom(XFSAccount):
+ __name__ = "LinestorageCom"
+ __type__ = "account"
+ __version__ = "0.03"
+
+ __description__ = """Linestorage.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "linestorage.com"
+ HOSTER_URL = "http://linestorage.com/"
diff --git a/module/plugins/accounts/LinksnappyCom.py b/module/plugins/accounts/LinksnappyCom.py
index 109478bde..19986157b 100644
--- a/module/plugins/accounts/LinksnappyCom.py
+++ b/module/plugins/accounts/LinksnappyCom.py
@@ -7,13 +7,13 @@ from module.common.json_layer import json_loads
class LinksnappyCom(Account):
- __name__ = "LinksnappyCom"
- __version__ = "0.02"
- __type__ = "account"
+ __name__ = "LinksnappyCom"
+ __type__ = "account"
+ __version__ = "0.03"
__description__ = """Linksnappy.com account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
def loadAccountInfo(self, user, req):
@@ -37,10 +37,11 @@ class LinksnappyCom(Account):
if 'trafficleft' not in j['return'] or isinstance(j['return']['trafficleft'], str):
trafficleft = -1
else:
- trafficleft = int(j['return']['trafficleft']) * 1024
+ trafficleft = self.parseTraffic(float(j['return']['trafficleft'] + "MB")
return {"premium": True, "validuntil": validuntil, "trafficleft": trafficleft}
+
def login(self, user, data, req):
r = req.load('http://gen.linksnappy.com/lseAPI.php',
get={'act': 'USERDETAILS', 'username': user, 'password': md5(data['password']).hexdigest()})
diff --git a/module/plugins/accounts/MegaDebridEu.py b/module/plugins/accounts/MegaDebridEu.py
index 769b6161b..a082b97af 100644
--- a/module/plugins/accounts/MegaDebridEu.py
+++ b/module/plugins/accounts/MegaDebridEu.py
@@ -1,31 +1,18 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
from module.plugins.Account import Account
from module.common.json_layer import json_loads
class MegaDebridEu(Account):
- __name__ = "MegaDebridEu"
- __version__ = "0.2"
- __type__ = "account"
+ __name__ = "MegaDebridEu"
+ __type__ = "account"
+ __version__ = "0.20"
__description__ = """mega-debrid.eu account plugin"""
- __author_name__ = "D.Ducatel"
- __author_mail__ = "dducatel@je-geek.fr"
+ __license__ = "GPLv3"
+ __authors__ = [("D.Ducatel", "dducatel@je-geek.fr")]
+
# Define the base URL of MegaDebrid api
API_URL = "https://www.mega-debrid.eu/api.php"
@@ -35,17 +22,18 @@ class MegaDebridEu(Account):
data = self.getAccountData(user)
jsonResponse = req.load(self.API_URL,
get={'action': 'connectUser', 'login': user, 'password': data['password']})
- response = json_loads(jsonResponse)
+ res = json_loads(jsonResponse)
- if response['response_code'] == "ok":
- return {"premium": True, "validuntil": float(response['vip_end']), "status": True}
+ if res['response_code'] == "ok":
+ return {"premium": True, "validuntil": float(res['vip_end']), "status": True}
else:
- self.logError(response)
+ self.logError(res)
return {"status": False, "premium": False}
+
def login(self, user, data, req):
jsonResponse = req.load(self.API_URL,
get={'action': 'connectUser', 'login': user, 'password': data['password']})
- response = json_loads(jsonResponse)
- if response['response_code'] != "ok":
+ res = json_loads(jsonResponse)
+ if res['response_code'] != "ok":
self.wrongPassword()
diff --git a/module/plugins/accounts/ShareRapidCom.py b/module/plugins/accounts/MegaRapidCz.py
index a1cb40130..41da7ac73 100644
--- a/module/plugins/accounts/ShareRapidCom.py
+++ b/module/plugins/accounts/MegaRapidCz.py
@@ -6,40 +6,47 @@ from time import mktime, strptime
from module.plugins.Account import Account
-class ShareRapidCom(Account):
- __name__ = "ShareRapidCom"
+class MegaRapidCz(Account):
+ __name__ = "MegaRapidCz"
+ __type__ = "account"
__version__ = "0.34"
- __type__ = "account"
__description__ = """MegaRapid.cz account plugin"""
- __author_name__ = ("MikyWoW", "zoidberg")
- __author_mail__ = ("mikywow@seznam.cz", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("MikyWoW", "mikywow@seznam.cz"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
login_timeout = 60
+ LIMITDL_PATTERN = ur'<td>Max. počet paralelních stahování: </td><td>(\d+)'
+ VALID_UNTIL_PATTERN = ur'<td>Paušální stahování aktivní. Vyprší </td><td><strong>(.*?)</strong>'
+ TRAFFIC_LEFT_PATTERN = r'<tr><td>Kredit</td><td>(.*?) GiB'
+
def loadAccountInfo(self, user, req):
- src = req.load("http://megarapid.cz/mujucet/", decode=True)
+ html = req.load("http://megarapid.cz/mujucet/", decode=True)
- m = re.search(ur'<td>Max. počet paralelních stahování: </td><td>(\d+)', src)
+ m = re.search(self.LIMITDL_PATTERN, html)
if m:
data = self.getAccountData(user)
data['options']['limitDL'] = [int(m.group(1))]
- m = re.search(ur'<td>Paušální stahování aktivní. Vyprší </td><td><strong>(.*?)</strong>', src)
+ m = re.search(self.VALID_UNTIL_PATTERN, html)
if m:
validuntil = mktime(strptime(m.group(1), "%d.%m.%Y - %H:%M"))
return {"premium": True, "trafficleft": -1, "validuntil": validuntil}
- m = re.search(r'<tr><td>Kredit</td><td>(.*?) GiB', src)
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
if m:
trafficleft = float(m.group(1)) * (1 << 20)
return {"premium": True, "trafficleft": trafficleft, "validuntil": -1}
return {"premium": False, "trafficleft": None, "validuntil": None}
+
def login(self, user, data, req):
- htm = req.load("http://megarapid.cz/prihlaseni/", cookies=True)
+ htm = req.load("http://megarapid.cz/prihlaseni/")
if "Heslo:" in htm:
start = htm.index('id="inp_hash" name="hash" value="')
htm = htm[start + 33:]
@@ -49,4 +56,4 @@ class ShareRapidCom(Account):
"login": user,
"pass1": data['password'],
"remember": 0,
- "sbmt": u"Přihlásit"}, cookies=True)
+ "sbmt": u"Přihlásit"})
diff --git a/module/plugins/accounts/MegasharesCom.py b/module/plugins/accounts/MegasharesCom.py
index 125a21699..6e0a4358e 100644
--- a/module/plugins/accounts/MegasharesCom.py
+++ b/module/plugins/accounts/MegasharesCom.py
@@ -7,13 +7,14 @@ from module.plugins.Account import Account
class MegasharesCom(Account):
- __name__ = "MegasharesCom"
+ __name__ = "MegasharesCom"
+ __type__ = "account"
__version__ = "0.02"
- __type__ = "account"
__description__ = """Megashares.com account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
VALID_UNTIL_PATTERN = r'<p class="premium_info_box">Period Ends: (\w{3} \d{1,2}, \d{4})</p>'
@@ -34,6 +35,7 @@ class MegasharesCom(Account):
return {"validuntil": validuntil, "trafficleft": -1, "premium": premium}
+
def login(self, user, data, req):
html = req.load('http://d01.megashares.com/myms_login.php', post={
"httpref": "",
diff --git a/module/plugins/accounts/MovReelCom.py b/module/plugins/accounts/MovReelCom.py
index 3ded0d960..6128cddc8 100644
--- a/module/plugins/accounts/MovReelCom.py
+++ b/module/plugins/accounts/MovReelCom.py
@@ -1,21 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.XFSPAccount import XFSPAccount
+from module.plugins.internal.XFSAccount import XFSAccount
-class MovReelCom(XFSPAccount):
- __name__ = "MovReelCom"
- __version__ = "0.01"
- __type__ = "account"
+class MovReelCom(XFSAccount):
+ __name__ = "MovReelCom"
+ __type__ = "account"
+ __version__ = "0.03"
__description__ = """Movreel.com account plugin"""
- __author_name__ = "t4skforce"
- __author_mail__ = "t4skforce1337[AT]gmail[DOT]com"
+ __license__ = "GPLv3"
+ __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")]
+
login_timeout = 60
info_threshold = 30
- MAIN_PAGE = "http://movreel.com/"
-
- TRAFFIC_LEFT_PATTERN = r'Traffic.*?<b>([^<]+)</b>'
- LOGIN_FAIL_PATTERN = r'<b[^>]*>Incorrect Login or Password</b><br>'
+ HOSTER_DOMAIN = "movreel.com"
diff --git a/module/plugins/accounts/MultiDebridCom.py b/module/plugins/accounts/MultiDebridCom.py
deleted file mode 100644
index 405dc60ac..000000000
--- a/module/plugins/accounts/MultiDebridCom.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from time import time
-
-from module.plugins.Account import Account
-from module.common.json_layer import json_loads
-
-
-class MultiDebridCom(Account):
- __name__ = "MultiDebridCom"
- __version__ = "0.01"
- __type__ = "account"
-
- __description__ = """Multi-debrid.com account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
-
- def loadAccountInfo(self, user, req):
- if 'days_left' in self.json_data:
- validuntil = int(time() + self.json_data['days_left'] * 24 * 60 * 60)
- return {"premium": True, "validuntil": validuntil, "trafficleft": -1}
- else:
- self.logError('Unable to get account information')
-
- def login(self, user, data, req):
- # Password to use is the API-Password written in http://multi-debrid.com/myaccount
- html = req.load("http://multi-debrid.com/api.php",
- get={"user": user, "pass": data['password']})
- self.logDebug('JSON data: ' + html)
- self.json_data = json_loads(html)
- if self.json_data['status'] != 'ok':
- self.logError('Invalid login. The password to use is the API-Password you find in your "My Account" page')
- self.wrongPassword()
diff --git a/module/plugins/accounts/MultishareCz.py b/module/plugins/accounts/MultishareCz.py
index 3d8852955..878413007 100644
--- a/module/plugins/accounts/MultishareCz.py
+++ b/module/plugins/accounts/MultishareCz.py
@@ -1,37 +1,21 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+import re
from module.plugins.Account import Account
-#from time import mktime, strptime
-#from pycurl import REFERER
-import re
-from module.utils import parseFileSize
class MultishareCz(Account):
- __name__ = "MultishareCz"
- __version__ = "0.02"
- __type__ = "account"
+ __name__ = "MultishareCz"
+ __type__ = "account"
+ __version__ = "0.04"
__description__ = """Multishare.cz account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- TRAFFIC_LEFT_PATTERN = r'<span class="profil-zvyrazneni">Kredit:</span>\s*<strong>(?P<S>[0-9,]+)&nbsp;(?P<U>\w+)</strong>'
+ TRAFFIC_LEFT_PATTERN = r'<span class="profil-zvyrazneni">Kredit:</span>\s*<strong>(?P<S>[\d.,]+)&nbsp;(?P<U>[\w^_]+)</strong>'
ACCOUNT_INFO_PATTERN = r'<input type="hidden" id="(u_ID|u_hash)" name="[^"]*" value="([^"]+)">'
@@ -40,7 +24,7 @@ class MultishareCz(Account):
html = req.load("http://www.multishare.cz/profil/", decode=True)
m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- trafficleft = parseFileSize(m.group('S'), m.group('U')) / 1024 if m else 0
+ trafficleft = self.parseTraffic(m.group('S') + m.group('U')) if m else 0
self.premium = True if trafficleft else False
html = req.load("http://www.multishare.cz/", decode=True)
@@ -48,6 +32,7 @@ class MultishareCz(Account):
return dict(mms_info, **{"validuntil": -1, "trafficleft": trafficleft})
+
def login(self, user, data, req):
html = req.load('http://www.multishare.cz/html/prihlaseni_process.php', post={
"akce": "Přihlásit",
diff --git a/module/plugins/accounts/MyfastfileCom.py b/module/plugins/accounts/MyfastfileCom.py
new file mode 100644
index 000000000..36923470e
--- /dev/null
+++ b/module/plugins/accounts/MyfastfileCom.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+
+from time import time
+
+from module.common.json_layer import json_loads
+from module.plugins.Account import Account
+
+
+class MyfastfileCom(Account):
+ __name__ = "MyfastfileCom"
+ __type__ = "account"
+ __version__ = "0.03"
+
+ __description__ = """Myfastfile.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
+
+ def loadAccountInfo(self, user, req):
+ if 'days_left' in self.json_data:
+ validuntil = time() + self.json_data['days_left'] * 24 * 60 * 60
+ return {"premium": True, "validuntil": validuntil, "trafficleft": -1}
+ else:
+ self.logError(_("Unable to get account information"))
+
+
+ def login(self, user, data, req):
+ # Password to use is the API-Password written in http://myfastfile.com/myaccount
+ html = req.load("http://myfastfile.com/api.php",
+ get={"user": user, "pass": data['password']})
+ self.logDebug("JSON data: " + html)
+ self.json_data = json_loads(html)
+ if self.json_data['status'] != 'ok':
+ self.logError(_('Invalid login. The password to use is the API-Password you find in your "My Account" page'))
+ self.wrongPassword()
diff --git a/module/plugins/accounts/NetloadIn.py b/module/plugins/accounts/NetloadIn.py
index 7c5ea69f8..15bad6966 100755
--- a/module/plugins/accounts/NetloadIn.py
+++ b/module/plugins/accounts/NetloadIn.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from time import time
@@ -22,19 +7,20 @@ from module.plugins.Account import Account
class NetloadIn(Account):
- __name__ = "NetloadIn"
+ __name__ = "NetloadIn"
+ __type__ = "account"
__version__ = "0.22"
- __type__ = "account"
__description__ = """Netload.in account plugin"""
- __author_name__ = ("RaNaN", "CryNickSystems")
- __author_mail__ = ("RaNaN@pyload.org", "webmaster@pcProfil.de")
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("CryNickSystems", "webmaster@pcProfil.de")]
def loadAccountInfo(self, user, req):
- page = req.load("http://netload.in/index.php?id=2&lang=de")
- left = r">(\d+) (Tag|Tage), (\d+) Stunden<"
- left = re.search(left, page)
+ html = req.load("http://netload.in/index.php", get={'id': 2, 'lang': "de"})
+ left = r'>(\d+) (Tag|Tage), (\d+) Stunden<'
+ left = re.search(left, html)
if left:
validuntil = time() + int(left.group(1)) * 24 * 60 * 60 + int(left.group(3)) * 60 * 60
trafficleft = -1
@@ -45,9 +31,10 @@ class NetloadIn(Account):
trafficleft = None
return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}
+
def login(self, user, data, req):
- page = req.load("http://netload.in/index.php", None,
+ html = req.load("http://netload.in/index.php", None,
{"txtuser": user, "txtpass": data['password'], "txtcheck": "login", "txtlogin": "Login"},
cookies=True)
- if "password or it might be invalid!" in page:
+ if "password or it might be invalid!" in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/NoPremiumPl.py b/module/plugins/accounts/NoPremiumPl.py
new file mode 100644
index 000000000..f2223b7d9
--- /dev/null
+++ b/module/plugins/accounts/NoPremiumPl.py
@@ -0,0 +1,81 @@
+# -*- 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:
+ # 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:
+ 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/module/plugins/accounts/NosuploadCom.py
new file mode 100644
index 000000000..e523ee2f4
--- /dev/null
+++ b/module/plugins/accounts/NosuploadCom.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class NosuploadCom(XFSAccount):
+ __name__ = "NosuploadCom"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Nosupload.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "nosupload.com"
diff --git a/module/plugins/accounts/NovafileCom.py b/module/plugins/accounts/NovafileCom.py
new file mode 100644
index 000000000..ab61bf0fc
--- /dev/null
+++ b/module/plugins/accounts/NovafileCom.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class NovafileCom(XFSAccount):
+ __name__ = "NovafileCom"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Novafile.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "novafile.com"
diff --git a/module/plugins/accounts/NowVideoSx.py b/module/plugins/accounts/NowVideoSx.py
new file mode 100644
index 000000000..e2dcaba12
--- /dev/null
+++ b/module/plugins/accounts/NowVideoSx.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from time import gmtime, mktime, strptime
+
+from module.plugins.Account import Account
+
+
+class NowVideoSx(Account):
+ __name__ = "NowVideoSx"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """NowVideo.at account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ VALID_UNTIL_PATTERN = r'>Your premium membership expires on: (.+?)<'
+
+
+ def loadAccountInfo(self, user, req):
+ validuntil = None
+ trafficleft = -1
+ premium = None
+
+ html = req.load("http://www.nowvideo.sx/premium.php")
+
+ m = re.search(self.VALID_UNTIL_PATTERN, html)
+ if m:
+ expiredate = m.group(1).strip()
+ self.logDebug("Expire date: " + expiredate)
+
+ try:
+ validuntil = mktime(strptime(expiredate, "%Y-%b-%d"))
+
+ except Exception, e:
+ self.logError(e)
+
+ else:
+ if validuntil > mktime(gmtime()):
+ premium = True
+ else:
+ premium = False
+ validuntil = -1
+
+ return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}
+
+
+ def login(self, user, data, req):
+ html = req.load("http://www.nowvideo.sx/login.php",
+ post={'user': user, 'pass': data['password']})
+
+ if ">Invalid login details" is html:
+ self.wrongPassword()
diff --git a/module/plugins/accounts/OboomCom.py b/module/plugins/accounts/OboomCom.py
index 97f7e930a..4d90e1b25 100644
--- a/module/plugins/accounts/OboomCom.py
+++ b/module/plugins/accounts/OboomCom.py
@@ -2,51 +2,61 @@
import time
-from module.plugins.Account import Account
-from module.lib.beaker.crypto.pbkdf2 import PBKDF2
+from beaker.crypto.pbkdf2 import PBKDF2
+
from module.common.json_layer import json_loads
+from module.plugins.Account import Account
class OboomCom(Account):
- __name__ = "OboomCom"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "OboomCom"
+ __type__ = "account"
+ __version__ = "0.22"
__description__ = """Oboom.com account plugin"""
- __author_name__ = "stanley"
- __author_mail__ = "stanley.foerster@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("stanley", "stanley.foerster@gmail.com")]
def loadAccountData(self, user, req):
passwd = self.getAccountData(user)['password']
salt = passwd[::-1]
pbkdf2 = PBKDF2(passwd, salt, 1000).hexread(16)
- result = json_loads(req.load("https://www.oboom.com/1.0/login", get={"auth": user, "pass": pbkdf2}))
+ result = json_loads(req.load("https://www.oboom.com/1/login", get={"auth": user, "pass": pbkdf2}))
if not result[0] == 200:
- self.logWarning("Failed to log in: %s" % result[1])
+ self.logWarning(_("Failed to log in: %s") % result[1])
self.wrongPassword()
return result[1]
+
def loadAccountInfo(self, name, req):
accountData = self.loadAccountData(name, req)
+
userData = accountData['user']
- if "premium_unix" in userData:
- validUntilUtc = int(userData['premium_unix'])
- if validUntilUtc > int(time.time()):
- premium = True
- validUntil = validUntilUtc
- traffic = userData['traffic']
- trafficLeft = traffic['current']
- maxTraffic = traffic['max']
- session = accountData['session']
- return {"premium": premium,
- "validuntil": validUntil,
- "trafficleft": trafficLeft / 1024,
- "maxtraffic": maxTraffic / 1024,
- "session": session
- }
- return {"premium": False, "validuntil": -1}
+ if userData['premium'] == "null":
+ premium = False
+ else:
+ premium = True
+
+ if userData['premium_unix'] == "null":
+ validUntil = -1
+ else:
+ validUntil = float(userData['premium_unix'])
+
+ traffic = userData['traffic']
+
+ trafficLeft = traffic['current'] / 1024 #@TODO: Remove `/ 1024` in 0.4.10
+ maxTraffic = traffic['max'] / 1024 #@TODO: Remove `/ 1024` in 0.4.10
+
+ session = accountData['session']
+
+ return {'premium' : premium,
+ 'validuntil' : validUntil,
+ 'trafficleft': trafficLeft,
+ 'maxtraffic' : maxTraffic,
+ 'session' : session}
+
def login(self, user, data, req):
self.loadAccountData(user, req)
diff --git a/module/plugins/accounts/OneFichierCom.py b/module/plugins/accounts/OneFichierCom.py
index be79423ef..2f1c914c1 100644
--- a/module/plugins/accounts/OneFichierCom.py
+++ b/module/plugins/accounts/OneFichierCom.py
@@ -1,48 +1,55 @@
# -*- coding: utf-8 -*-
import re
+
from time import strptime, mktime
+
from pycurl import REFERER
from module.plugins.Account import Account
class OneFichierCom(Account):
- __name__ = "OneFichierCom"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "OneFichierCom"
+ __type__ = "account"
+ __version__ = "0.11"
__description__ = """1fichier.com account plugin"""
- __author_name__ = "Elrick69"
- __author_mail__ = "elrick69[AT]rocketmail[DOT]com"
+ __license__ = "GPLv3"
+ __authors__ = [("Elrick69", "elrick69[AT]rocketmail[DOT]com"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
- VALID_UNTIL_PATTERN = r'You are a premium user until (?P<d>\d{2})/(?P<m>\d{2})/(?P<y>\d{4})'
+
+ VALID_UNTIL_PATTERN = r'Your Premium Status will end the (\d+/\d+/\d+)'
def loadAccountInfo(self, user, req):
+ validuntil = None
+ trafficleft = -1
+ premium = None
- html = req.load("http://1fichier.com/console/abo.pl")
+ html = req.load("https://1fichier.com/console/abo.pl")
m = re.search(self.VALID_UNTIL_PATTERN, html)
-
if m:
- premium = True
- validuntil = re.sub(self.VALID_UNTIL_PATTERN, '\g<d>/\g<m>/\g<y>', m.group(0))
- validuntil = int(mktime(strptime(validuntil, "%d/%m/%Y")))
- else:
- premium = False
- validuntil = -1
+ expiredate = m.group(1)
+ self.logDebug("Expire date: " + expiredate)
- return {"premium": premium, "trafficleft": -1, "validuntil": validuntil}
+ try:
+ validuntil = mktime(strptime(expiredate, "%d/%m/%Y"))
+ except Exception, e:
+ self.logError(e)
+ else:
+ premium = True
+
+ return {'validuntil': validuntil, 'trafficleft': trafficleft, 'premium': premium or False}
- def login(self, user, data, req):
- req.http.c.setopt(REFERER, "http://1fichier.com/login.pl?lg=en")
+ def login(self, user, data, req):
+ req.http.c.setopt(REFERER, "https://1fichier.com/login.pl?lg=en")
- html = req.load("http://1fichier.com/login.pl?lg=en", post={
- "mail": user,
- "pass": data['password'],
- "Login": "Login"})
+ html = req.load("https://1fichier.com/login.pl?lg=en",
+ post={'mail': user, 'pass': data['password'], 'It': "on", 'purge': "off", 'valider': "Send"})
- if r'<div class="error_message">Invalid username or password.</div>' in html:
+ if '>Invalid email address' in html or '>Invalid password' in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/OverLoadMe.py b/module/plugins/accounts/OverLoadMe.py
index 129074a0f..fb9732986 100644
--- a/module/plugins/accounts/OverLoadMe.py
+++ b/module/plugins/accounts/OverLoadMe.py
@@ -5,19 +5,19 @@ from module.common.json_layer import json_loads
class OverLoadMe(Account):
- __name__ = "OverLoadMe"
+ __name__ = "OverLoadMe"
+ __type__ = "account"
__version__ = "0.01"
- __type__ = "account"
__description__ = """Over-Load.me account plugin"""
- __author_name__ = "marley"
- __author_mail__ = "marley@over-load.me"
+ __license__ = "GPLv3"
+ __authors__ = [("marley", "marley@over-load.me")]
def loadAccountInfo(self, user, req):
data = self.getAccountData(user)
- page = req.load("https://api.over-load.me/account.php", get={"user": user, "auth": data['password']}).strip()
- data = json_loads(page)
+ html = req.load("https://api.over-load.me/account.php", get={"user": user, "auth": data['password']}).strip()
+ data = json_loads(html)
# Check for premium
if data['membership'] == "Free":
@@ -26,6 +26,7 @@ class OverLoadMe(Account):
account_info = {"validuntil": data['expirationunix'], "trafficleft": -1}
return account_info
+
def login(self, user, data, req):
jsondata = req.load("https://api.over-load.me/account.php",
get={"user": user, "auth": data['password']}).strip()
diff --git a/module/plugins/accounts/Premium4Me.py b/module/plugins/accounts/Premium4Me.py
deleted file mode 100644
index 9eab6f81f..000000000
--- a/module/plugins/accounts/Premium4Me.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from module.plugins.Account import Account
-
-
-class Premium4Me(Account):
- __name__ = "Premium4Me"
- __version__ = "0.03"
- __type__ = "account"
-
- __description__ = """Premium.to account plugin"""
- __author_name__ = ("RaNaN", "zoidberg", "stickell")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz", "l.stickell@yahoo.it")
-
-
- def loadAccountInfo(self, user, req):
- traffic = req.load("http://premium.to/api/traffic.php?authcode=%s" % self.authcode)
-
- account_info = {"trafficleft": int(traffic) / 1024,
- "validuntil": -1}
-
- return account_info
-
- def login(self, user, data, req):
- self.authcode = req.load("http://premium.to/api/getauthcode.php?username=%s&password=%s" % (
- user, data['password'])).strip()
-
- if "wrong username" in self.authcode:
- self.wrongPassword()
diff --git a/module/plugins/accounts/PremiumTo.py b/module/plugins/accounts/PremiumTo.py
new file mode 100644
index 000000000..ef3d0cc19
--- /dev/null
+++ b/module/plugins/accounts/PremiumTo.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.Account import Account
+
+
+class PremiumTo(Account):
+ __name__ = "PremiumTo"
+ __type__ = "account"
+ __version__ = "0.05"
+
+ __description__ = """Premium.to account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
+
+ def loadAccountInfo(self, user, req):
+ api_r = req.load("http://premium.to/api/straffic.php",
+ get={'username': self.username, 'password': self.password})
+
+ trafficleft = sum(map(float, api_r.split(';'))) / 1024 #@TODO: Remove `/ 1024` in 0.4.10
+
+ return {'premium': True, 'trafficleft': trafficleft, 'validuntil': -1}
+
+
+ def login(self, user, data, req):
+ self.username = user
+ self.password = data['password']
+ authcode = req.load("http://premium.to/api/getauthcode.php",
+ get={'username': user, 'password': self.password}).strip()
+
+ if "wrong username" in authcode:
+ self.wrongPassword()
diff --git a/module/plugins/accounts/PremiumizeMe.py b/module/plugins/accounts/PremiumizeMe.py
index 83eade048..c1abde309 100644
--- a/module/plugins/accounts/PremiumizeMe.py
+++ b/module/plugins/accounts/PremiumizeMe.py
@@ -6,13 +6,13 @@ from module.common.json_layer import json_loads
class PremiumizeMe(Account):
- __name__ = "PremiumizeMe"
- __version__ = "0.11"
- __type__ = "account"
+ __name__ = "PremiumizeMe"
+ __type__ = "account"
+ __version__ = "0.12"
__description__ = """Premiumize.me account plugin"""
- __author_name__ = "Florian Franzen"
- __author_mail__ = "FlorianFranzen@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Florian Franzen", "FlorianFranzen@gmail.com")]
def loadAccountInfo(self, user, req):
@@ -22,13 +22,14 @@ class PremiumizeMe(Account):
# Parse account info
account_info = {"validuntil": float(status['result']['expires']),
- "trafficleft": max(0, status['result']['trafficleft_bytes'] / 1024)}
+ "trafficleft": max(0, status['result']['trafficleft_bytes'] / 1024)} #@TODO: Remove `/ 1024` in 0.4.10
if status['result']['type'] == 'free':
account_info['premium'] = False
return account_info
+
def login(self, user, data, req):
# Get user data from premiumize.me
status = self.getAccountStatus(user, req)
@@ -37,10 +38,12 @@ class PremiumizeMe(Account):
if status['status'] != 200:
self.wrongPassword()
+
def getAccountStatus(self, user, req):
# Use premiumize.me API v1 (see https://secure.premiumize.me/?show=api)
# to retrieve account info and return the parsed json answer
- answer = req.load(
- "https://api.premiumize.me/pm-api/v1.php?method=accountstatus&params[login]=%s&params[pass]=%s" % (
- user, self.accounts[user]['password']))
+ answer = req.load("https://api.premiumize.me/pm-api/v1.php",
+ get={'method' : "accountstatus",
+ 'params[login]': user,
+ 'params[pass]' : self.accounts[user]['password']})
return json_loads(answer)
diff --git a/module/plugins/accounts/QuickshareCz.py b/module/plugins/accounts/QuickshareCz.py
index 34a3a971a..18af5f736 100644
--- a/module/plugins/accounts/QuickshareCz.py
+++ b/module/plugins/accounts/QuickshareCz.py
@@ -1,41 +1,29 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.Account import Account
-from module.utils import parseFileSize
class QuickshareCz(Account):
- __name__ = "QuickshareCz"
- __version__ = "0.01"
- __type__ = "account"
+ __name__ = "QuickshareCz"
+ __type__ = "account"
+ __version__ = "0.02"
__description__ = """Quickshare.cz account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ TRAFFIC_LEFT_PATTERN = r'Stav kreditu: <strong>(.+?)</strong>'
def loadAccountInfo(self, user, req):
html = req.load("http://www.quickshare.cz/premium", decode=True)
- m = re.search(r'Stav kreditu: <strong>(.+?)</strong>', html)
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
if m:
- trafficleft = parseFileSize(m.group(1)) / 1024
+ trafficleft = self.parseTraffic(m.group(1))
premium = True if trafficleft else False
else:
trafficleft = None
@@ -43,6 +31,7 @@ class QuickshareCz(Account):
return {"validuntil": -1, "trafficleft": trafficleft, "premium": premium}
+
def login(self, user, data, req):
html = req.load('http://www.quickshare.cz/html/prihlaseni_process.php', post={
"akce": u'Přihlásit',
diff --git a/module/plugins/accounts/RPNetBiz.py b/module/plugins/accounts/RPNetBiz.py
index 08bedda7d..813453c03 100644
--- a/module/plugins/accounts/RPNetBiz.py
+++ b/module/plugins/accounts/RPNetBiz.py
@@ -5,22 +5,22 @@ from module.common.json_layer import json_loads
class RPNetBiz(Account):
- __name__ = "RPNetBiz"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "RPNetBiz"
+ __type__ = "account"
+ __version__ = "0.11"
__description__ = """RPNet.biz account plugin"""
- __author_name__ = "Dman"
- __author_mail__ = "dmanugm@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Dman", "dmanugm@gmail.com")]
def loadAccountInfo(self, user, req):
# Get account information from rpnet.biz
- response = self.getAccountStatus(user, req)
+ res = self.getAccountStatus(user, req)
try:
- if response['accountInfo']['isPremium']:
+ if res['accountInfo']['isPremium']:
# Parse account info. Change the trafficleft later to support per host info.
- account_info = {"validuntil": int(response['accountInfo']['premiumExpiry']),
+ account_info = {"validuntil": float(res['accountInfo']['premiumExpiry']),
"trafficleft": -1, "premium": True}
else:
account_info = {"validuntil": None, "trafficleft": None, "premium": False}
@@ -31,19 +31,21 @@ class RPNetBiz(Account):
return account_info
+
def login(self, user, data, req):
# Get account information from rpnet.biz
- response = self.getAccountStatus(user, req)
+ res = self.getAccountStatus(user, req)
- # If we have an error in the response, we have wrong login information
- if 'error' in response:
+ # If we have an error in the res, we have wrong login information
+ if 'error' in res:
self.wrongPassword()
+
def getAccountStatus(self, user, req):
# Using the rpnet API, check if valid premium account
- response = req.load("https://premium.rpnet.biz/client_api.php",
+ res = req.load("https://premium.rpnet.biz/client_api.php",
get={"username": user, "password": self.accounts[user]['password'],
"action": "showAccountInformation"})
- self.logDebug("JSON data: %s" % response)
+ self.logDebug("JSON data: %s" % res)
- return json_loads(response)
+ return json_loads(res)
diff --git a/module/plugins/accounts/RapideoPl.py b/module/plugins/accounts/RapideoPl.py
new file mode 100644
index 000000000..438ce7ad3
--- /dev/null
+++ b/module/plugins/accounts/RapideoPl.py
@@ -0,0 +1,80 @@
+# -*- 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:
+ # 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:
+ 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/module/plugins/accounts/RapidfileshareNet.py
new file mode 100644
index 000000000..c0dd7eaee
--- /dev/null
+++ b/module/plugins/accounts/RapidfileshareNet.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class RapidfileshareNet(XFSAccount):
+ __name__ = "RapidfileshareNet"
+ __type__ = "account"
+ __version__ = "0.05"
+
+ __description__ = """Rapidfileshare.net account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("guidobelix", "guidobelix@hotmail.it")]
+
+
+ HOSTER_DOMAIN = "rapidfileshare.net"
+
+ TRAFFIC_LEFT_PATTERN = r'>Traffic available today:</TD><TD><label for="name">\s*(?P<S>[\d.,]+)\s*(?:(?P<U>[\w^_]+))?'
diff --git a/module/plugins/accounts/RapidgatorNet.py b/module/plugins/accounts/RapidgatorNet.py
index 05d31e6a0..2899d5a68 100644
--- a/module/plugins/accounts/RapidgatorNet.py
+++ b/module/plugins/accounts/RapidgatorNet.py
@@ -1,32 +1,18 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.Account import Account
from module.common.json_layer import json_loads
class RapidgatorNet(Account):
- __name__ = "RapidgatorNet"
- __version__ = "0.04"
- __type__ = "account"
+ __name__ = "RapidgatorNet"
+ __type__ = "account"
+ __version__ = "0.05"
__description__ = """Rapidgator.net account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
API_URL = 'http://rapidgator.net/api/user'
@@ -45,7 +31,7 @@ class RapidgatorNet(Account):
self.scheduleRefresh(user, json['response']['reset_in'])
return {"validuntil": json['response']['expire_date'],
- "trafficleft": int(json['response']['traffic_left']) / 1024,
+ "trafficleft": float(json['response']['traffic_left']) / 1024, #@TODO: Remove `/ 1024` in 0.4.10
"premium": True}
else:
self.logError(json['response_details'])
@@ -54,6 +40,7 @@ class RapidgatorNet(Account):
return {"validuntil": None, "trafficleft": None, "premium": False}
+
def login(self, user, data, req):
try:
json = req.load('%s/login' % self.API_URL, post={"username": user, "password": data['password']})
diff --git a/module/plugins/accounts/RapidshareCom.py b/module/plugins/accounts/RapidshareCom.py
deleted file mode 100644
index 6745813d9..000000000
--- a/module/plugins/accounts/RapidshareCom.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-from module.plugins.Account import Account
-
-
-class RapidshareCom(Account):
- __name__ = "RapidshareCom"
- __version__ = "0.22"
- __type__ = "account"
-
- __description__ = """Rapidshare.com account plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
-
-
- def loadAccountInfo(self, user, req):
- data = self.getAccountData(user)
- api_url_base = "http://api.rapidshare.com/cgi-bin/rsapi.cgi"
- api_param_prem = {"sub": "getaccountdetails", "type": "prem", "login": user,
- "password": data['password'], "withcookie": 1}
- src = req.load(api_url_base, cookies=False, get=api_param_prem)
- if src.startswith("ERROR"):
- raise Exception(src)
- fields = src.split("\n")
- info = {}
- for t in fields:
- if not t.strip():
- continue
- k, v = t.split("=")
- info[k] = v
-
- validuntil = int(info['billeduntil'])
- premium = True if validuntil else False
-
- tmp = {"premium": premium, "validuntil": validuntil, "trafficleft": -1, "maxtraffic": -1}
-
- return tmp
-
- def login(self, user, data, req):
- api_url_base = "http://api.rapidshare.com/cgi-bin/rsapi.cgi"
- api_param_prem = {"sub": "getaccountdetails", "type": "prem", "login": user,
- "password": data['password'], "withcookie": 1}
- src = req.load(api_url_base, cookies=False, get=api_param_prem)
- if src.startswith("ERROR"):
- raise Exception(src + "### Note you have to use your account number for login, instead of name.")
- fields = src.split("\n")
- info = {}
- for t in fields:
- if not t.strip():
- continue
- k, v = t.split("=")
- info[k] = v
- cj = self.getAccountCookies(user)
- cj.setCookie("rapidshare.com", "enc", info['cookie'])
diff --git a/module/plugins/accounts/RapiduNet.py b/module/plugins/accounts/RapiduNet.py
new file mode 100644
index 000000000..fe465bc48
--- /dev/null
+++ b/module/plugins/accounts/RapiduNet.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+
+import re
+from module.plugins.Account import Account
+from module.common.json_layer import json_loads
+
+
+class RapiduNet(Account):
+ __name__ = "RapiduNet"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Rapidu.net account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("prOq", None)]
+
+
+ PREMIUM_PATTERN = r'<a href="premium/" style="padding-left: 0px;">Account: <b>Premium</b></a>'
+
+
+ def loadAccountInfo(self, user, req):
+ info = {'validuntil': None, 'trafficleft': None, 'premium': False}
+
+ req.load("https://rapidu.net/ajax.php", get={'a': "getChangeLang"}, post={"_go": "", "lang": "en"})
+ html = req.load("https://rapidu.net/", decode=True)
+
+ if re.search(self.PREMIUM_PATTERN, html):
+ info['premium'] = True
+
+ return info
+
+
+ def login(self, user, data, req):
+ try:
+ json = json_loads(req.load("https://rapidu.net/ajax.php?a=getUserLogin",
+ post={'_go': "",
+ 'login': user,
+ 'pass': data['password'],
+ 'member': "1"}))
+
+ self.logDebug(json)
+
+ if not json['message'] == "success":
+ self.wrongPassword()
+
+ except Exception, e:
+ self.logError(e)
diff --git a/module/plugins/accounts/RarefileNet.py b/module/plugins/accounts/RarefileNet.py
index 2424eaff5..577a6c8f6 100644
--- a/module/plugins/accounts/RarefileNet.py
+++ b/module/plugins/accounts/RarefileNet.py
@@ -1,15 +1,16 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.XFSPAccount import XFSPAccount
+from module.plugins.internal.XFSAccount import XFSAccount
-class RarefileNet(XFSPAccount):
- __name__ = "RarefileNet"
- __version__ = "0.02"
- __type__ = "account"
+class RarefileNet(XFSAccount):
+ __name__ = "RarefileNet"
+ __type__ = "account"
+ __version__ = "0.04"
__description__ = """RareFile.net account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- MAIN_PAGE = "http://rarefile.net/"
+
+ HOSTER_DOMAIN = "rarefile.net"
diff --git a/module/plugins/accounts/RealdebridCom.py b/module/plugins/accounts/RealdebridCom.py
index 8ca4112e9..48b17df5f 100644
--- a/module/plugins/accounts/RealdebridCom.py
+++ b/module/plugins/accounts/RealdebridCom.py
@@ -6,30 +6,31 @@ from module.plugins.Account import Account
class RealdebridCom(Account):
- __name__ = "RealdebridCom"
- __version__ = "0.43"
- __type__ = "account"
+ __name__ = "RealdebridCom"
+ __type__ = "account"
+ __version__ = "0.44"
__description__ = """Real-Debrid.com account plugin"""
- __author_name__ = "Devirex Hazzard"
- __author_mail__ = "naibaf_11@yahoo.de"
+ __license__ = "GPLv3"
+ __authors__ = [("Devirex Hazzard", "naibaf_11@yahoo.de")]
def loadAccountInfo(self, user, req):
if self.pin_code:
return {"premium": False}
- page = req.load("https://real-debrid.com/api/account.php")
- xml = dom.parseString(page)
- account_info = {"validuntil": int(xml.getElementsByTagName("expiration")[0].childNodes[0].nodeValue),
+ html = req.load("https://real-debrid.com/api/account.php")
+ xml = dom.parseString(html)
+ account_info = {"validuntil": float(xml.getElementsByTagName("expiration")[0].childNodes[0].nodeValue),
"trafficleft": -1}
return account_info
+
def login(self, user, data, req):
self.pin_code = False
- page = req.load("https://real-debrid.com/ajax/login.php", get={"user": user, "pass": data['password']})
- if "Your login informations are incorrect" in page:
+ html = req.load("https://real-debrid.com/ajax/login.php", get={"user": user, "pass": data['password']})
+ if "Your login informations are incorrect" in html:
self.wrongPassword()
- elif "PIN Code required" in page:
- self.logWarning('PIN code required. Please login to https://real-debrid.com using the PIN or disable the double authentication in your control panel on https://real-debrid.com.')
+ elif "PIN Code required" in html:
+ self.logWarning(_("PIN code required. Please login to https://real-debrid.com using the PIN or disable the double authentication in your control panel on https://real-debrid.com"))
self.pin_code = True
diff --git a/module/plugins/accounts/RehostTo.py b/module/plugins/accounts/RehostTo.py
index 7a6263ab3..00a45dedd 100644
--- a/module/plugins/accounts/RehostTo.py
+++ b/module/plugins/accounts/RehostTo.py
@@ -4,34 +4,42 @@ from module.plugins.Account import Account
class RehostTo(Account):
- __name__ = "RehostTo"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "RehostTo"
+ __type__ = "account"
+ __version__ = "0.11"
__description__ = """Rehost.to account plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
def loadAccountInfo(self, user, req):
data = self.getAccountData(user)
- page = req.load("http://rehost.to/api.php?cmd=login&user=%s&pass=%s" % (user, data['password']))
- data = [x.split("=") for x in page.split(",")]
+ html = req.load("http://rehost.to/api.php",
+ get={'cmd': "login", 'user': user, 'pass': data['password']})
+ data = [x.split("=") for x in html.split(",")]
ses = data[0][1]
long_ses = data[1][1]
- page = req.load("http://rehost.to/api.php?cmd=get_premium_credits&long_ses=%s" % long_ses)
- traffic, valid = page.split(",")
+ html = req.load("http://rehost.to/api.php",
+ get={'cmd': "get_premium_credits", 'long_ses': long_ses})
- account_info = {"trafficleft": int(traffic) * 1024,
- "validuntil": int(valid),
- "long_ses": long_ses,
- "ses": ses}
+ traffic, valid = html.split(",")
+
+ trafficleft = self.parseTraffic(traffic + "MB")
+ validuntil = float(valid)
+
+ account_info = {"trafficleft": trafficleft,
+ "validuntil" : validuntil,
+ "long_ses" : long_ses,
+ "ses" : ses}
return account_info
+
def login(self, user, data, req):
- page = req.load("http://rehost.to/api.php?cmd=login&user=%s&pass=%s" % (user, data['password']))
+ html = req.load("http://rehost.to/api.php",
+ get={'cmd': "login", 'user': user, 'pass': data['password']})
- if "Login failed." in page:
+ if "Login failed." in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/RyushareCom.py b/module/plugins/accounts/RyushareCom.py
index fc092f82a..ca476366b 100644
--- a/module/plugins/accounts/RyushareCom.py
+++ b/module/plugins/accounts/RyushareCom.py
@@ -1,18 +1,20 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.XFSPAccount import XFSPAccount
+from module.plugins.internal.XFSAccount import XFSAccount
-class RyushareCom(XFSPAccount):
- __name__ = "RyushareCom"
- __version__ = "0.03"
- __type__ = "account"
+class RyushareCom(XFSAccount):
+ __name__ = "RyushareCom"
+ __type__ = "account"
+ __version__ = "0.05"
__description__ = """Ryushare.com account plugin"""
- __author_name__ = ("zoidberg", "trance4us")
- __author_mail__ = ("zoidberg@mujmail.cz", "")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("trance4us", None)]
- MAIN_PAGE = "http://ryushare.com/"
+
+ HOSTER_DOMAIN = "ryushare.com"
def login(self, user, data, req):
diff --git a/module/plugins/accounts/SafesharingEu.py b/module/plugins/accounts/SafesharingEu.py
new file mode 100644
index 000000000..2e58d33b3
--- /dev/null
+++ b/module/plugins/accounts/SafesharingEu.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class SafesharingEu(XFSAccount):
+ __name__ = "SafesharingEu"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Safesharing.eu account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("guidobelix", "guidobelix@hotmail.it")]
+
+
+ HOSTER_DOMAIN = "safesharing.eu"
diff --git a/module/plugins/accounts/SecureUploadEu.py b/module/plugins/accounts/SecureUploadEu.py
new file mode 100644
index 000000000..b335c94da
--- /dev/null
+++ b/module/plugins/accounts/SecureUploadEu.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class SecureUploadEu(XFSAccount):
+ __name__ = "SecureUploadEu"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """SecureUpload.eu account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "secureupload.eu"
diff --git a/module/plugins/accounts/SendmywayCom.py b/module/plugins/accounts/SendmywayCom.py
new file mode 100644
index 000000000..4fcbe0b7a
--- /dev/null
+++ b/module/plugins/accounts/SendmywayCom.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class SendmywayCom(XFSAccount):
+ __name__ = "SendmywayCom"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Sendmyway.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "sendmyway.com"
diff --git a/module/plugins/accounts/ShareonlineBiz.py b/module/plugins/accounts/ShareonlineBiz.py
index 9f706d186..056f14876 100644
--- a/module/plugins/accounts/ShareonlineBiz.py
+++ b/module/plugins/accounts/ShareonlineBiz.py
@@ -1,57 +1,64 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.Account import Account
class ShareonlineBiz(Account):
- __name__ = "ShareonlineBiz"
- __version__ = "0.24"
- __type__ = "account"
+ __name__ = "ShareonlineBiz"
+ __type__ = "account"
+ __version__ = "0.27"
__description__ = """Share-online.biz account plugin"""
- __author_name__ = ("mkaay", "zoidberg")
- __author_mail__ = ("mkaay@mkaay.de", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("mkaay", "mkaay@mkaay.de"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
- def getUserAPI(self, user, req):
- return req.load("http://api.share-online.biz/account.php",
- {"username": user, "password": self.accounts[user]['password'], "act": "userDetails"})
+ def api_response(self, user, req):
+ return req.load("http://api.share-online.biz/cgi-bin",
+ get={'q': "userdetails", 'aux': "traffic", "username": user, "password": self.accounts[user]['password']})
+
def loadAccountInfo(self, user, req):
- src = self.getUserAPI(user, req)
+ premium = False
+ validuntil = None
+ trafficleft = -1
+ maxtraffic = 100 * 1024 * 1024 * 1024 #: 100 GB
- info = {}
- for line in src.splitlines():
+ api = {}
+ for line in self.api_response(user, req).splitlines():
if "=" in line:
key, value = line.split("=")
- info[key] = value
- self.logDebug(info)
+ api[key] = value
+
+ self.logDebug(api)
+
+ for key in ("dl", "a"):
+ if key not in api:
+ continue
+
+ if api['group'] != "Sammler":
+ premium = True
+
+ if api[key].lower() != "not_available":
+ req.cj.setCookie("share-online.biz", key, api[key])
+ break
+
+ if 'expire_date' in api:
+ validuntil = float(api['expire_date'])
+
+ if 'traffic_1d' in api:
+ traffic = float(api['traffic_1d'].split(";")[0])
+ maxtraffic = max(maxtraffic, traffic)
+ trafficleft = maxtraffic - traffic
- if "dl" in info and info['dl'].lower() != "not_available":
- req.cj.setCookie("share-online.biz", "dl", info['dl'])
- if "a" in info and info['a'].lower() != "not_available":
- req.cj.setCookie("share-online.biz", "a", info['a'])
+ return {'premium': premium, 'validuntil': validuntil, 'trafficleft': trafficleft, 'maxtraffic': maxtraffic}
- return {"validuntil": int(info['expire_date']) if "expire_date" in info else -1,
- "trafficleft": -1,
- "premium": True if ("dl" in info or "a" in info) and (info['group'] != "Sammler") else False}
def login(self, user, data, req):
- src = self.getUserAPI(user, req)
- if "EXCEPTION" in src:
+ html = self.api_response(user, req)
+ err = re.search(r'**(.+?)**', html)
+ if err:
+ self.logError(err.group(1))
self.wrongPassword()
diff --git a/module/plugins/accounts/SimplyPremiumCom.py b/module/plugins/accounts/SimplyPremiumCom.py
index 6eace8838..465757457 100644
--- a/module/plugins/accounts/SimplyPremiumCom.py
+++ b/module/plugins/accounts/SimplyPremiumCom.py
@@ -1,34 +1,23 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
from module.common.json_layer import json_loads
from module.plugins.Account import Account
class SimplyPremiumCom(Account):
- __name__ = "SimplyPremiumCom"
- __version__ = "0.01"
- __type__ = "account"
+ __name__ = "SimplyPremiumCom"
+ __type__ = "account"
+ __version__ = "0.02"
__description__ = """Simply-Premium.com account plugin"""
- __author_name__ = "EvolutionClip"
- __author_mail__ = "evolutionclip@live.de"
+ __license__ = "GPLv3"
+ __authors__ = [("EvolutionClip", "evolutionclip@live.de")]
def loadAccountInfo(self, user, req):
+ validuntil = -1
+ trafficleft = None
+
json_data = req.load('http://www.simply-premium.com/api/user.php?format=json')
self.logDebug("JSON data: " + json_data)
json_data = json_loads(json_data)
@@ -36,14 +25,14 @@ class SimplyPremiumCom(Account):
if 'vip' in json_data['result'] and json_data['result']['vip'] == 0:
return {"premium": False}
- #Time package
- validuntil = float(json_data['result']['timeend'])
- #Traffic package
- # {"trafficleft": int(traffic) / 1024, "validuntil": -1}
- #trafficleft = int(json_data['result']['traffic'] / 1024)
+ if 'timeend' in json_data['result'] and json_data['result']['timeend']:
+ validuntil = float(json_data['result']['timeend'])
+
+ if 'traffic' in json_data['result'] and json_data['result']['traffic']:
+ trafficleft = float(json_data['result']['traffic']) / 1024 #@TODO: Remove `/ 1024` in 0.4.10
+
+ return {"premium": True, "validuntil": validuntil, "trafficleft": trafficleft}
- #return {"premium": True, "validuntil": validuntil, "trafficleft": trafficleft}
- return {"premium": True, "validuntil": validuntil}
def login(self, user, data, req):
req.cj.setCookie("simply-premium.com", "lang", "EN")
diff --git a/module/plugins/accounts/SimplydebridCom.py b/module/plugins/accounts/SimplydebridCom.py
index a3803b088..406534364 100644
--- a/module/plugins/accounts/SimplydebridCom.py
+++ b/module/plugins/accounts/SimplydebridCom.py
@@ -6,28 +6,29 @@ from module.plugins.Account import Account
class SimplydebridCom(Account):
- __name__ = "SimplydebridCom"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "SimplydebridCom"
+ __type__ = "account"
+ __version__ = "0.10"
__description__ = """Simply-Debrid.com account plugin"""
- __author_name__ = "Kagenoshin"
- __author_mail__ = "kagenoshin@gmx.ch"
+ __license__ = "GPLv3"
+ __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")]
def loadAccountInfo(self, user, req):
get_data = {'login': 2, 'u': self.loginname, 'p': self.password}
- response = req.load("http://simply-debrid.com/api.php", get=get_data, decode=True)
- data = [x.strip() for x in response.split(";")]
+ res = req.load("http://simply-debrid.com/api.php", get=get_data, decode=True)
+ data = [x.strip() for x in res.split(";")]
if str(data[0]) != "1":
return {"premium": False}
else:
return {"trafficleft": -1, "validuntil": mktime(strptime(str(data[2]), "%d/%m/%Y"))}
+
def login(self, user, data, req):
self.loginname = user
self.password = data['password']
get_data = {'login': 1, 'u': self.loginname, 'p': self.password}
- response = req.load("http://simply-debrid.com/api.php", get=get_data, decode=True)
- if response != "02: loggin success":
+ res = req.load("http://simply-debrid.com/api.php", get=get_data, decode=True)
+ if res != "02: loggin success":
self.wrongPassword()
diff --git a/module/plugins/accounts/StahnuTo.py b/module/plugins/accounts/StahnuTo.py
index e22030cdf..2b08c67cd 100644
--- a/module/plugins/accounts/StahnuTo.py
+++ b/module/plugins/accounts/StahnuTo.py
@@ -1,43 +1,28 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from module.plugins.Account import Account
-from module.utils import parseFileSize
class StahnuTo(Account):
- __name__ = "StahnuTo"
- __version__ = "0.02"
- __type__ = "account"
+ __name__ = "StahnuTo"
+ __type__ = "account"
+ __version__ = "0.04"
__description__ = """StahnuTo account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
def loadAccountInfo(self, user, req):
html = req.load("http://www.stahnu.to/")
m = re.search(r'>VIP: (\d+.*)<', html)
- trafficleft = parseFileSize(m.group(1)) * 1024 if m else 0
+ trafficleft = self.parseTraffic(m.group(1)) if m else 0
+
+ return {"premium": trafficleft > 512, "trafficleft": trafficleft, "validuntil": -1}
- return {"premium": trafficleft > (512 * 1024), "trafficleft": trafficleft, "validuntil": -1}
def login(self, user, data, req):
html = req.load("http://www.stahnu.to/login.php", post={
diff --git a/module/plugins/accounts/StreamcloudEu.py b/module/plugins/accounts/StreamcloudEu.py
new file mode 100644
index 000000000..aa1eafcbd
--- /dev/null
+++ b/module/plugins/accounts/StreamcloudEu.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class StreamcloudEu(XFSAccount):
+ __name__ = "StreamcloudEu"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Streamcloud.eu account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "streamcloud.eu"
diff --git a/module/plugins/accounts/TurbobitNet.py b/module/plugins/accounts/TurbobitNet.py
index 7e0f8b8a7..f87d234a7 100644
--- a/module/plugins/accounts/TurbobitNet.py
+++ b/module/plugins/accounts/TurbobitNet.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from time import mktime, strptime
@@ -22,19 +7,19 @@ from module.plugins.Account import Account
class TurbobitNet(Account):
- __name__ = "TurbobitNet"
+ __name__ = "TurbobitNet"
+ __type__ = "account"
__version__ = "0.01"
- __type__ = "account"
__description__ = """TurbobitNet account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
def loadAccountInfo(self, user, req):
html = req.load("http://turbobit.net")
- m = re.search(r'<u>Turbo Access</u> to ([0-9.]+)', html)
+ m = re.search(r'<u>Turbo Access</u> to ([\d.]+)', html)
if m:
premium = True
validuntil = mktime(strptime(m.group(1), "%d.%m.%Y"))
@@ -44,6 +29,7 @@ class TurbobitNet(Account):
return {"premium": premium, "trafficleft": -1, "validuntil": validuntil}
+
def login(self, user, data, req):
req.cj.setCookie("turbobit.net", "user_lang", "en")
diff --git a/module/plugins/accounts/TusfilesNet.py b/module/plugins/accounts/TusfilesNet.py
new file mode 100644
index 000000000..279dfd00a
--- /dev/null
+++ b/module/plugins/accounts/TusfilesNet.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from time import mktime, strptime, gmtime
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class TusfilesNet(XFSAccount):
+ __name__ = "TusfilesNet"
+ __type__ = "account"
+ __version__ = "0.06"
+
+ __description__ = """ Tusfile.net account plugin """
+ __license__ = "GPLv3"
+ __authors__ = [("guidobelix", "guidobelix@hotmail.it")]
+
+
+ HOSTER_DOMAIN = "tusfiles.net"
+
+ VALID_UNTIL_PATTERN = r'<span class="label label-default">([^<]+)</span>'
+ TRAFFIC_LEFT_PATTERN = r'<td><img src="//www\.tusfiles\.net/i/icon/meter\.png" alt=""/></td>\n<td>&nbsp;(?P<S>[\d.,]+)'
diff --git a/module/plugins/accounts/UlozTo.py b/module/plugins/accounts/UlozTo.py
index 689ad0a9a..7236a4fa8 100644
--- a/module/plugins/accounts/UlozTo.py
+++ b/module/plugins/accounts/UlozTo.py
@@ -2,44 +2,49 @@
import re
+from urlparse import urljoin
+
from module.plugins.Account import Account
class UlozTo(Account):
- __name__ = "UlozTo"
- __version__ = "0.06"
- __type__ = "account"
+ __name__ = "UlozTo"
+ __type__ = "account"
+ __version__ = "0.10"
__description__ = """Uloz.to account plugin"""
- __author_name__ = ("zoidberg", "pulpe")
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("pulpe", None)]
+
- TRAFFIC_LEFT_PATTERN = r'<li class="menu-kredit"><a href="/kredit" title="[^"]*?GB = ([0-9.]+) MB"'
+ TRAFFIC_LEFT_PATTERN = r'<li class="menu-kredit"><a .*?title="[^"]*?GB = ([\d.]+) MB"'
def loadAccountInfo(self, user, req):
- #this cookie gets lost somehow after each request
- self.phpsessid = req.cj.getCookie("ULOSESSID")
html = req.load("http://www.ulozto.net/", decode=True)
- req.cj.setCookie("www.ulozto.net", "ULOSESSID", self.phpsessid)
m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- trafficleft = int(float(m.group(1).replace(' ', '').replace(',', '.')) * 1000 * 1.048) if m else 0
- self.premium = True if trafficleft else False
- return {"validuntil": -1, "trafficleft": trafficleft}
+ trafficleft = float(m.group(1).replace(' ', '').replace(',', '.')) * 1000 * 1.048 if m else 0
+ premium = True if trafficleft else False
+
+ return {'validuntil': -1, 'trafficleft': trafficleft, 'premium': premium}
+
def login(self, user, data, req):
login_page = req.load('http://www.ulozto.net/?do=web-login', decode=True)
- action = re.findall('<form action="(.+?)"', login_page)[1].replace('&amp;', '&')
- token = re.search('_token_" value="(.+?)"', login_page).group(1)
-
- html = req.load('http://www.ulozto.net'+action, post={
- "_token_": token,
- "login": "Submit",
- "password": data['password'],
- "username": user
- }, decode=True)
+ action = re.findall('<form action="(.+?)"', login_page)[1].replace('&amp;', '&')
+ token = re.search('_token_" value="(.+?)"', login_page).group(1)
+
+ html = req.load(urljoin("http://www.ulozto.net/", action),
+ post={'_token_' : token,
+ 'do' : "loginForm-submit",
+ 'login' : u"Přihlásit",
+ 'password': data['password'],
+ 'username': user,
+ 'remember': "on"},
+ decode=True)
if '<div class="flash error">' in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/UnrestrictLi.py b/module/plugins/accounts/UnrestrictLi.py
index 94452b966..f5db3f888 100644
--- a/module/plugins/accounts/UnrestrictLi.py
+++ b/module/plugins/accounts/UnrestrictLi.py
@@ -1,31 +1,17 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
from module.plugins.Account import Account
from module.common.json_layer import json_loads
class UnrestrictLi(Account):
- __name__ = "UnrestrictLi"
- __version__ = "0.03"
- __type__ = "account"
+ __name__ = "UnrestrictLi"
+ __type__ = "account"
+ __version__ = "0.04"
__description__ = """Unrestrict.li account plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
def loadAccountInfo(self, user, req):
@@ -37,16 +23,17 @@ class UnrestrictLi(Account):
return {"premium": False}
validuntil = json_data['result']['expires']
- trafficleft = int(json_data['result']['traffic'] / 1024)
+ trafficleft = float(json_data['result']['traffic'] / 1024) #@TODO: Remove `/ 1024` in 0.4.10
return {"premium": True, "validuntil": validuntil, "trafficleft": trafficleft}
+
def login(self, user, data, req):
req.cj.setCookie("unrestrict.li", "lang", "EN")
html = req.load("https://unrestrict.li/sign_in")
if 'solvemedia' in html:
- self.logError("A Captcha is required. Go to http://unrestrict.li/sign_in and login, then retry")
+ self.logError(_("A Captcha is required. Go to http://unrestrict.li/sign_in and login, then retry"))
return
post_data = {"username": user, "password": data['password'],
diff --git a/module/plugins/accounts/UploadcCom.py b/module/plugins/accounts/UploadcCom.py
new file mode 100644
index 000000000..d1e1a2ead
--- /dev/null
+++ b/module/plugins/accounts/UploadcCom.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class UploadcCom(XFSAccount):
+ __name__ = "UploadcCom"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Uploadc.com account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "uploadc.com"
diff --git a/module/plugins/accounts/UploadedTo.py b/module/plugins/accounts/UploadedTo.py
index bde76be9f..c09726799 100644
--- a/module/plugins/accounts/UploadedTo.py
+++ b/module/plugins/accounts/UploadedTo.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from time import time
@@ -22,47 +7,62 @@ from module.plugins.Account import Account
class UploadedTo(Account):
- __name__ = "UploadedTo"
- __version__ = "0.26"
- __type__ = "account"
+ __name__ = "UploadedTo"
+ __type__ = "account"
+ __version__ = "0.29"
__description__ = """Uploaded.to account plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ PREMIUM_PATTERN = r'<em>Premium</em>'
+ VALID_UNTIL_PATTERN = r'<td>Duration:</td>\s*<th>(.+?)<'
+ TRAFFIC_LEFT_PATTERN = r'<b class="cB">(?P<S>[\d.,]+) (?P<U>[\w^_]+)'
def loadAccountInfo(self, user, req):
+ validuntil = None
+ trafficleft = None
+ premium = None
- req.load("http://uploaded.net/language/en")
html = req.load("http://uploaded.net/me")
- premium = '<a href="register"><em>Premium</em>' in html or '<em>Premium</em></th>' in html
+ premium = True if re.search(self.PREMIUM_PATTERN, html) else False
- if premium:
- raw_traffic = re.search(r'<th colspan="2"><b class="cB">([^<]+)', html).group(1).replace('.', '')
- raw_valid = re.search(r"<td>Duration:</td>\s*<th>([^<]+)", html, re.MULTILINE).group(1).strip()
+ m = re.search(self.VALID_UNTIL_PATTERN, html, re.M)
+ if m:
+ expiredate = m.group(1).lower().strip()
- traffic = int(self.parseTraffic(raw_traffic))
-
- if raw_valid == "unlimited":
+ if expiredate == "unlimited":
validuntil = -1
else:
- raw_valid = re.findall(r"(\d+) (Week|weeks|days|day|hours|hour)", raw_valid)
- validuntil = time()
- for n, u in raw_valid:
- validuntil += int(n) * 60 * 60 * {"Week": 168, "weeks": 168, "days": 24,
- "day": 24, "hours": 1, "hour": 1}[u]
+ m = re.findall(r'(\d+) (week|day|hour)', expiredate)
+ if m:
+ validuntil = time()
+ for n, u in m:
+ validuntil += float(n) * 60 * 60 * {'week': 168, 'day': 24, 'hour': 1}[u]
+
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+ if m:
+ traffic = m.groupdict()
+ size = traffic['S'].replace('.', '')
+ unit = traffic['U'].lower()
+
+ if unit.startswith('t'): #@NOTE: Remove in 0.4.10
+ trafficleft = float(size.replace(',', '.')) / 1024
+ trafficleft *= 1 << 40
+ else:
+ trafficleft = self.parseTraffic(size + unit)
- return {"validuntil": validuntil, "trafficleft": traffic, "maxtraffic": 50 * 1024 * 1024}
- else:
- return {"premium": False, "validuntil": -1}
+ return {'validuntil': validuntil, 'trafficleft': trafficleft, 'premium': premium}
- def login(self, user, data, req):
- req.load("http://uploaded.net/language/en")
+ def login(self, user, data, req):
req.cj.setCookie("uploaded.net", "lang", "en")
- page = req.load("http://uploaded.net/io/login", post={"id": user, "pw": data['password'], "_": ""})
+ html = req.load("http://uploaded.net/io/login",
+ post={'id': user, 'pw': data['password'], '_': ""})
- if "User and password do not match!" in page:
+ if "User and password do not match" in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/UploadheroCom.py b/module/plugins/accounts/UploadheroCom.py
index 681ef6f6a..1e30b3771 100644
--- a/module/plugins/accounts/UploadheroCom.py
+++ b/module/plugins/accounts/UploadheroCom.py
@@ -8,23 +8,23 @@ from module.plugins.Account import Account
class UploadheroCom(Account):
- __name__ = "UploadheroCom"
- __version__ = "0.2"
- __type__ = "account"
+ __name__ = "UploadheroCom"
+ __type__ = "account"
+ __version__ = "0.20"
__description__ = """Uploadhero.co account plugin"""
- __author_name__ = "mcmyst"
- __author_mail__ = "mcmyst@hotmail.fr"
+ __license__ = "GPLv3"
+ __authors__ = [("mcmyst", "mcmyst@hotmail.fr")]
def loadAccountInfo(self, user, req):
- premium_pattern = re.compile('Il vous reste <span class="bleu">([0-9]+)</span> jours premium.')
+ premium_pattern = re.compile('Il vous reste <span class="bleu">(\d+)</span> jours premium')
data = self.getAccountData(user)
- page = req.load("http://uploadhero.co/my-account")
+ html = req.load("http://uploadhero.co/my-account")
- if premium_pattern.search(page):
- end_date = datetime.date.today() + datetime.timedelta(days=int(premium_pattern.search(page).group(1)))
+ if premium_pattern.search(html):
+ end_date = datetime.date.today() + datetime.timedelta(days=int(premium_pattern.search(html).group(1)))
end_date = time.mktime(future.timetuple())
account_info = {"validuntil": end_date, "trafficleft": -1, "premium": True}
else:
@@ -32,9 +32,10 @@ class UploadheroCom(Account):
return account_info
+
def login(self, user, data, req):
- page = req.load("http://uploadhero.co/lib/connexion.php",
+ html = req.load("http://uploadhero.co/lib/connexion.php",
post={"pseudo_login": user, "password_login": data['password']})
- if "mot de passe invalide" in page:
+ if "mot de passe invalide" in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/UploadingCom.py b/module/plugins/accounts/UploadingCom.py
index f07c2941a..c70d2ec11 100644
--- a/module/plugins/accounts/UploadingCom.py
+++ b/module/plugins/accounts/UploadingCom.py
@@ -1,55 +1,63 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+import re
from time import time, strptime, mktime
-import re
from module.plugins.Account import Account
+from module.plugins.internal.SimpleHoster import set_cookies
class UploadingCom(Account):
- __name__ = "UploadingCom"
- __version__ = "0.1"
- __type__ = "account"
+ __name__ = "UploadingCom"
+ __type__ = "account"
+ __version__ = "0.11"
__description__ = """Uploading.com account plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __license__ = "GPLv3"
+ __authors__ = [("mkaay", "mkaay@mkaay.de")]
+
+
+ PREMIUM_PATTERN = r'UPGRADE TO PREMIUM'
+ VALID_UNTIL_PATTERN = r'Valid Until:(.+?)<'
def loadAccountInfo(self, user, req):
- src = req.load("http://uploading.com/")
- premium = True
- if "UPGRADE TO PREMIUM" in src:
- return {"validuntil": -1, "trafficleft": -1, "premium": False}
+ validuntil = None
+ trafficleft = None
+ premium = None
+
+ html = req.load("http://uploading.com/")
- m = re.search("Valid Until:(.*?)<", src)
+ premium = False if re.search(self.PREMIUM_PATTERN, html) else True
+
+ m = re.search(self.VALID_UNTIL_PATTERN, html)
if m:
- validuntil = int(mktime(strptime(m.group(1).strip(), "%b %d, %Y")))
- else:
- validuntil = -1
+ expiredate = m.group(1).strip()
+ self.logDebug("Expire date: " + expiredate)
+
+ try:
+ validuntil = mktime(strptime(expiredate, "%b %d, %Y"))
+
+ except Exception, e:
+ self.logError(e)
+
+ else:
+ if validuntil > mktime(gmtime()):
+ premium = True
+ else:
+ premium = False
+ validuntil = None
+
+ return {'validuntil': validuntil, 'trafficleft': trafficleft, 'premium': premium}
- return {"validuntil": validuntil, "trafficleft": -1, "premium": True}
def login(self, user, data, req):
- req.cj.setCookie("uploading.com", "lang", "1")
- req.cj.setCookie("uploading.com", "language", "1")
- req.cj.setCookie("uploading.com", "setlang", "en")
- req.cj.setCookie("uploading.com", "_lang", "en")
+ set_cookies([("uploading.com", "lang", "1"),
+ ("uploading.com", "language", "1"),
+ ("uploading.com", "setlang", "en"),
+ ("uploading.com", "_lang", "en")]
+
req.load("http://uploading.com/")
req.load("http://uploading.com/general/login_form/?JsHttpRequest=%s-xml" % long(time() * 1000),
- post={"email": user, "password": data['password'], "remember": "on"})
+ post={'email': user, 'password': data['password'], 'remember': "on"})
diff --git a/module/plugins/accounts/UptoboxCom.py b/module/plugins/accounts/UptoboxCom.py
index 16016f41d..299a0acc2 100644
--- a/module/plugins/accounts/UptoboxCom.py
+++ b/module/plugins/accounts/UptoboxCom.py
@@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.XFSPAccount import XFSPAccount
+from module.plugins.internal.XFSAccount import XFSAccount
-class UptoboxCom(XFSPAccount):
- __name__ = "UptoboxCom"
- __version__ = "0.02"
- __type__ = "account"
+class UptoboxCom(XFSAccount):
+ __name__ = "UptoboxCom"
+ __type__ = "account"
+ __version__ = "0.07"
__description__ = """DDLStorage.com account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- MAIN_PAGE = "http://uptobox.com/"
- VALID_UNTIL_PATTERN = r'>Premium.[Aa]ccount expire: ([^<]+)</strong>'
+ HOSTER_DOMAIN = "uptobox.com"
+ HOSTER_URL = "https://uptobox.com/"
diff --git a/module/plugins/accounts/VidPlayNet.py b/module/plugins/accounts/VidPlayNet.py
new file mode 100644
index 000000000..5bfc24963
--- /dev/null
+++ b/module/plugins/accounts/VidPlayNet.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class VidPlayNet(XFSAccount):
+ __name__ = "VidPlayNet"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """VidPlay.net account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "vidplay.net"
diff --git a/module/plugins/accounts/WebshareCz.py b/module/plugins/accounts/WebshareCz.py
new file mode 100644
index 000000000..f8e3eeb73
--- /dev/null
+++ b/module/plugins/accounts/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 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/accounts/XFileSharingPro.py b/module/plugins/accounts/XFileSharingPro.py
new file mode 100644
index 000000000..8dc7f3a30
--- /dev/null
+++ b/module/plugins/accounts/XFileSharingPro.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSAccount import XFSAccount
+
+
+class XFileSharingPro(XFSAccount):
+ __name__ = "XFileSharingPro"
+ __type__ = "account"
+ __version__ = "0.06"
+
+ __description__ = """XFileSharingPro multi-purpose account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = None
+
+
+ def init(self):
+ if self.HOSTER_DOMAIN:
+ return super(XFileSharingPro, self).init()
+
+
+ def loadAccountInfo(self, user, req):
+ return super(XFileSharingPro if self.HOSTER_DOMAIN else XFSAccount, self).loadAccountInfo(user, req)
+
+
+ def login(self, user, data, req):
+ if self.HOSTER_DOMAIN:
+ try:
+ return super(XFileSharingPro, self).login(user, data, req)
+ except Exception:
+ self.HOSTER_URL = self.HOSTER_URL.replace("www.", "")
+ return super(XFileSharingPro, self).login(user, data, req)
diff --git a/module/plugins/accounts/YibaishiwuCom.py b/module/plugins/accounts/YibaishiwuCom.py
index 1894258a3..92a6bfedf 100644
--- a/module/plugins/accounts/YibaishiwuCom.py
+++ b/module/plugins/accounts/YibaishiwuCom.py
@@ -1,33 +1,19 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from module.plugins.Account import Account
class YibaishiwuCom(Account):
- __name__ = "YibaishiwuCom"
+ __name__ = "YibaishiwuCom"
+ __type__ = "account"
__version__ = "0.01"
- __type__ = "account"
__description__ = """115.com account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
ACCOUNT_INFO_PATTERN = r'var USER_PERMISSION = {(.*?)}'
@@ -41,6 +27,7 @@ class YibaishiwuCom(Account):
validuntil = trafficleft = (-1 if m else 0)
return dict({"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium})
+
def login(self, user, data, req):
html = req.load('http://passport.115.com/?ac=login', post={
"back": "http://www.115.com/",
diff --git a/module/plugins/accounts/ZeveraCom.py b/module/plugins/accounts/ZeveraCom.py
index 11a224039..e8e3431e3 100644
--- a/module/plugins/accounts/ZeveraCom.py
+++ b/module/plugins/accounts/ZeveraCom.py
@@ -6,13 +6,13 @@ from module.plugins.Account import Account
class ZeveraCom(Account):
- __name__ = "ZeveraCom"
- __version__ = "0.21"
- __type__ = "account"
+ __name__ = "ZeveraCom"
+ __type__ = "account"
+ __version__ = "0.22"
__description__ = """Zevera.com account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
def loadAccountInfo(self, user, req):
@@ -21,18 +21,20 @@ class ZeveraCom(Account):
account_info = {"trafficleft": 0, "validuntil": 0, "premium": False}
else:
account_info = {
- "trafficleft": int(data['availabletodaytraffic']) * 1024,
+ "trafficleft": float(data['availabletodaytraffic']) * 1024,
"validuntil": mktime(strptime(data['endsubscriptiondate'], "%Y/%m/%d %H:%M:%S")),
"premium": True
}
return account_info
+
def login(self, user, data, req):
self.loginname = user
self.password = data['password']
if self.getAPIData(req) == "No traffic":
self.wrongPassword()
+
def getAPIData(self, req, just_header=False, **kwargs):
get_data = {
'cmd': 'accountinfo',
@@ -41,14 +43,14 @@ class ZeveraCom(Account):
}
get_data.update(kwargs)
- response = req.load("http://www.zevera.com/jDownloader.ashx", get=get_data,
+ res = req.load("http://www.zevera.com/jDownloader.ashx", get=get_data,
decode=True, just_header=just_header)
- self.logDebug(response)
+ self.logDebug(res)
- if ':' in response:
+ if ':' in res:
if not just_header:
- response = response.replace(',', '\n')
+ res = res.replace(',', '\n')
return dict((y.strip().lower(), z.strip()) for (y, z) in
- [x.split(':', 1) for x in response.splitlines() if ':' in x])
+ [x.split(':', 1) for x in res.splitlines() if ':' in x])
else:
- return response
+ return res
diff --git a/module/plugins/captcha/GigasizeCom.py b/module/plugins/captcha/GigasizeCom.py
index 1f77e420d..244cf6a2a 100644
--- a/module/plugins/captcha/GigasizeCom.py
+++ b/module/plugins/captcha/GigasizeCom.py
@@ -1,21 +1,22 @@
# -*- coding: utf-8 -*-
-from captcha import OCR
+from module.plugins.captcha.captcha import OCR
class GigasizeCom(OCR):
- __name__ = "GigasizeCom"
- __version__ = "0.1"
- __type__ = "ocr"
+ __name__ = "GigasizeCom"
+ __type__ = "ocr"
+ __version__ = "0.10"
__description__ = """Gigasize.com ocr plugin"""
- __author_name__ = "pyLoad Team"
- __author_mail__ = "admin@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
def __init__(self):
OCR.__init__(self)
+
def get_captcha(self, image):
self.load_image(image)
self.threshold(2.8)
diff --git a/module/plugins/captcha/LinksaveIn.py b/module/plugins/captcha/LinksaveIn.py
index da36cf552..56cbd58a0 100644
--- a/module/plugins/captcha/LinksaveIn.py
+++ b/module/plugins/captcha/LinksaveIn.py
@@ -1,27 +1,32 @@
# -*- coding: utf-8 -*-
-from PIL import Image
+try:
+ from PIL import Image
+except ImportError:
+ import Image
+
from glob import glob
from os import sep
from os.path import abspath, dirname
-from captcha import OCR
+from module.plugins.captcha.captcha import OCR
class LinksaveIn(OCR):
- __name__ = "LinksaveIn"
- __version__ = "0.1"
- __type__ = "ocr"
+ __name__ = "LinksaveIn"
+ __type__ = "ocr"
+ __version__ = "0.10"
__description__ = """Linksave.in ocr plugin"""
- __author_name__ = "pyLoad Team"
- __author_mail__ = "admin@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
def __init__(self):
OCR.__init__(self)
self.data_dir = dirname(abspath(__file__)) + sep + "LinksaveIn" + sep
+
def load_image(self, image):
im = Image.open(image)
frame_nr = 0
@@ -49,6 +54,7 @@ class LinksaveIn(OCR):
self.pixels = self.image.load()
self.result_captcha = ''
+
def get_bg(self):
stat = {}
cstat = {}
@@ -79,12 +85,13 @@ class LinksaveIn(OCR):
stat[bgpath] += 1
max_p = 0
bg = ""
- for bgpath, value in stat.items():
+ for bgpath, value in stat.iteritems():
if max_p < value:
bg = bgpath
max_p = value
return bg
+
def substract_bg(self, bgpath):
bg = Image.open(bgpath)
img = self.image.convert("P")
@@ -107,6 +114,7 @@ class LinksaveIn(OCR):
if rgb_c == rgb_bg:
orgpix[x, y] = (255,255,255)
+
def eval_black_white(self):
new = Image.new("RGB", (140, 75))
pix = new.load()
@@ -128,6 +136,7 @@ class LinksaveIn(OCR):
self.image = new
self.pixels = self.image.load()
+
def get_captcha(self, image):
self.load_image(image)
bg = self.get_bg()
diff --git a/module/plugins/captcha/NetloadIn.py b/module/plugins/captcha/NetloadIn.py
index 4585b51df..28eb18fb5 100644
--- a/module/plugins/captcha/NetloadIn.py
+++ b/module/plugins/captcha/NetloadIn.py
@@ -1,21 +1,22 @@
# -*- coding: utf-8 -*-
-from captcha import OCR
+from module.plugins.captcha.captcha import OCR
class NetloadIn(OCR):
- __name__ = "NetloadIn"
- __version__ = "0.1"
- __type__ = "ocr"
+ __name__ = "NetloadIn"
+ __type__ = "ocr"
+ __version__ = "0.10"
__description__ = """Netload.in ocr plugin"""
- __author_name__ = "pyLoad Team"
- __author_mail__ = "admin@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
def __init__(self):
OCR.__init__(self)
+
def get_captcha(self, image):
self.load_image(image)
self.to_greyscale()
diff --git a/module/plugins/captcha/ShareonlineBiz.py b/module/plugins/captcha/ShareonlineBiz.py
index 44ea6a187..8210e8859 100644
--- a/module/plugins/captcha/ShareonlineBiz.py
+++ b/module/plugins/captcha/ShareonlineBiz.py
@@ -1,21 +1,22 @@
# -*- coding: utf-8 -*-
-from captcha import OCR
+from module.plugins.captcha.captcha import OCR
class ShareonlineBiz(OCR):
- __name__ = "ShareonlineBiz"
- __version__ = "0.1"
- __type__ = "ocr"
+ __name__ = "ShareonlineBiz"
+ __type__ = "ocr"
+ __version__ = "0.10"
__description__ = """Shareonline.biz ocr plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
def __init__(self):
OCR.__init__(self)
+
def get_captcha(self, image):
self.load_image(image)
self.to_greyscale()
diff --git a/module/plugins/captcha/captcha.py b/module/plugins/captcha/captcha.py
index 061228c99..0f233ec00 100644
--- a/module/plugins/captcha/captcha.py
+++ b/module/plugins/captcha/captcha.py
@@ -1,62 +1,49 @@
# -*- coding: utf-8 -*-
-#
-#Copyright (C) 2009 kingzero, RaNaN
-#
-#This program is free software; you can redistribute it and/or modify
-#it under the terms of the GNU General Public License as published by
-#the Free Software Foundation; either version 3 of the License,
-#or (at your option) any later version.
-#
-#This program is distributed in the hope that it will be useful,
-#but WITHOUT ANY WARRANTY; without even the implied warranty of
-#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-#See the GNU General Public License for more details.
-#
-#You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
-###
from __future__ import with_statement
-import os
-from os.path import join
-from os.path import abspath
+
+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
-import Image
-import TiffImagePlugin
-import PngImagePlugin
-import GifImagePlugin
-import JpegImagePlugin
+from os.path import abspath, join
class OCR(object):
- __name__ = "OCR"
- __type__ = "ocr"
- __version__ = "0.1"
+ __name__ = "OCR"
+ __type__ = "ocr"
+ __version__ = "0.10"
__description__ = """OCR base plugin"""
- __author_name__ = "pyLoad Team"
- __author_mail__ = "admin@pyload.org"
+ __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"""
@@ -67,42 +54,46 @@ class OCR(object):
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):
- #self.logger.debug("create tmp tif")
+ #tmpTif = tempfile.NamedTemporaryFile(suffix=".tif")
+ try:
+ tmpTif = open(join("tmp", "tmpTif_%s.tif" % self.__name__), "wb")
+ tmpTif.close()
+
+ #tmpTxt = tempfile.NamedTemporaryFile(suffix=".txt")
+ tmpTxt = open(join("tmp", "tmpTxt_%s.txt" % self.__name__), "wb")
+ tmpTxt.close()
- #tmp = tempfile.NamedTemporaryFile(suffix=".tif")
- tmp = open(join("tmp", "tmpTif_%s.tif" % self.__name__), "wb")
- tmp.close()
- #self.logger.debug("create tmp txt")
- #tmpTxt = tempfile.NamedTemporaryFile(suffix=".txt")
- tmpTxt = open(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(tmp.name, 'TIFF')
+ self.image.save(tmpTif.name, 'TIFF')
if os.name == "nt":
- tessparams = [join(pypath,"tesseract","tesseract.exe")]
+ tessparams = [join(pypath, "tesseract", "tesseract.exe")]
else:
tessparams = ["tesseract"]
- tessparams.extend( [abspath(tmp.name), abspath(tmpTxt.name).replace(".txt", "")] )
+ tessparams.extend( [abspath(tmpTif.name), abspath(tmpTxt.name).replace(".txt", "")] )
if subset and (digits or lowercase or uppercase):
- #self.logger.debug("create temp subset config")
#tmpSub = tempfile.NamedTemporaryFile(suffix=".subset")
- tmpSub = open(join("tmp", "tmpSub_%s.subset" % self.__name__), "wb")
- 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(abspath(tmpSub.name))
- tmpSub.close()
+ with open(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(abspath(tmpSub.name))
self.logger.debug("run tesseract")
self.run(tessparams)
@@ -116,22 +107,25 @@ class OCR(object):
self.logger.debug(self.result_captcha)
try:
- os.remove(tmp.name)
+ os.remove(tmpTif.name)
os.remove(tmpTxt.name)
if subset and (digits or lowercase or uppercase):
os.remove(tmpSub.name)
except:
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
@@ -142,6 +136,7 @@ class OCR(object):
else:
self.pixels[x, y] = 0
+
def clean(self, allowed):
pixels = self.pixels
@@ -187,6 +182,7 @@ class OCR(object):
self.pixels = pixels
+
def derotate_by_average(self):
"""rotate by checking each angle and guess most suitable"""
@@ -261,6 +257,7 @@ class OCR(object):
self.pixels = pixels
+
def split_captcha_letters(self):
captcha = self.image
started = False
@@ -300,6 +297,7 @@ class OCR(object):
return letters
+
def correct(self, values, var=None):
if var:
result = var
@@ -318,14 +316,3 @@ class OCR(object):
return result
else:
self.result_captcha = result
-
-
-if __name__ == '__main__':
- ocr = OCR()
- ocr.load_image("B.jpg")
- ocr.to_greyscale()
- ocr.eval_black_white(140)
- ocr.derotate_by_average()
- ocr.run_tesser()
- print "Tesseract", ocr.result_captcha
- ocr.image.save("derotated.jpg")
diff --git a/module/plugins/container/CCF.py b/module/plugins/container/CCF.py
index a5a071820..bca535175 100644
--- a/module/plugins/container/CCF.py
+++ b/module/plugins/container/CCF.py
@@ -1,28 +1,31 @@
# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
import re
from os import makedirs
-from os.path import exists, join
+from os.path import exists
from urllib2 import build_opener
-from module.lib.MultipartPostHandler import MultipartPostHandler
+from MultipartPostHandler import MultipartPostHandler
+
from module.plugins.Container import Container
+from module.utils import save_join
class CCF(Container):
- __name__ = "CCF"
- __version__ = "0.2"
+ __name__ = "CCF"
+ __version__ = "0.20"
__pattern__ = r'.+\.ccf'
__description__ = """CCF container decrypter plugin"""
- __author_name__ = "Willnix"
- __author_mail__ = "Willnix@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("Willnix", "Willnix@pyload.org")]
def decrypt(self, pyfile):
-
infile = pyfile.url.replace("\n", "")
opener = build_opener(MultipartPostHandler)
@@ -32,13 +35,9 @@ class CCF(Container):
tempdlc_content = opener.open('http://service.jdownloader.net/dlcrypt/getDLC.php', params).read()
download_folder = self.config['general']['download_folder']
- location = download_folder #join(download_folder, pyfile.package().folder.decode(sys.getfilesystemencoding()))
- if not exists(location):
- makedirs(location)
-
- tempdlc_name = join(location, "tmp_%s.dlc" % pyfile.name)
- tempdlc = open(tempdlc_name, "w")
- tempdlc.write(re.search(r'<dlc>(.*)</dlc>', tempdlc_content, re.DOTALL).group(1))
- tempdlc.close()
+
+ tempdlc_name = save_join(download_folder, "tmp_%s.dlc" % pyfile.name)
+ with open(tempdlc_name, "w") as tempdlc:
+ tempdlc.write(re.search(r'<dlc>(.*)</dlc>', tempdlc_content, re.S).group(1))
self.urls = [tempdlc_name]
diff --git a/module/plugins/container/DLC_25.pyc b/module/plugins/container/DLC_25.pyc
index b8fde0051..409264902 100644
--- a/module/plugins/container/DLC_25.pyc
+++ b/module/plugins/container/DLC_25.pyc
Binary files differ
diff --git a/module/plugins/container/DLC_26.pyc b/module/plugins/container/DLC_26.pyc
index 41a4e0cb8..685995fc2 100644
--- a/module/plugins/container/DLC_26.pyc
+++ b/module/plugins/container/DLC_26.pyc
Binary files differ
diff --git a/module/plugins/container/DLC_27.pyc b/module/plugins/container/DLC_27.pyc
index a6bffaf74..6c6d663e5 100644
--- a/module/plugins/container/DLC_27.pyc
+++ b/module/plugins/container/DLC_27.pyc
Binary files differ
diff --git a/module/plugins/container/LinkList.py b/module/plugins/container/LinkList.py
index 7e418bd67..c6173ad73 100644
--- a/module/plugins/container/LinkList.py
+++ b/module/plugins/container/LinkList.py
@@ -7,7 +7,7 @@ from module.utils import fs_encode
class LinkList(Container):
- __name__ = "LinkList"
+ __name__ = "LinkList"
__version__ = "0.12"
__pattern__ = r'.+\.txt'
@@ -15,8 +15,9 @@ class LinkList(Container):
("encoding", "string", "File encoding (default utf-8)", "")]
__description__ = """Read link lists in txt format"""
- __author_name__ = ("spoob", "jeix")
- __author_mail__ = ("spoob@pyload.org", "jeix@hasnomail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org"),
+ ("jeix", "jeix@hasnomail.com")]
def decrypt(self, pyfile):
@@ -25,9 +26,6 @@ class LinkList(Container):
except:
file_enc = "utf-8"
- print repr(pyfile.url)
- print pyfile.url
-
file_name = fs_encode(pyfile.url)
txt = codecs.open(file_name, 'r', file_enc)
@@ -67,7 +65,7 @@ class LinkList(Container):
txt = open(file_name, 'wb')
txt.close()
except:
- self.logWarning(_("LinkList could not be cleared."))
+ self.logWarning(_("LinkList could not be cleared"))
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
index c35efacc6..0c43f0e6c 100644
--- a/module/plugins/container/RSDF.py
+++ b/module/plugins/container/RSDF.py
@@ -1,28 +1,32 @@
# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
import base64
import binascii
import re
from module.plugins.Container import Container
+from module.utils import fs_encode
class RSDF(Container):
- __name__ = "RSDF"
- __version__ = "0.22"
+ __name__ = "RSDF"
+ __version__ = "0.24"
__pattern__ = r'.+\.rsdf'
__description__ = """RSDF container decrypter plugin"""
- __author_name__ = ("RaNaN", "spoob")
- __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org")
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("spoob", "spoob@pyload.org")]
def decrypt(self, pyfile):
from Crypto.Cipher import AES
- infile = pyfile.url.replace("\n", "")
+ infile = fs_encode(pyfile.url.replace("\n", ""))
Key = binascii.unhexlify('8C35192D964DC3182C6F84F3252239EB4A320D2500000000')
IV = binascii.unhexlify('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')
@@ -31,10 +35,11 @@ class RSDF(Container):
obj = AES.new(Key, AES.MODE_CFB, IV)
- rsdf = open(infile, 'r')
-
- data = rsdf.read()
- rsdf.close()
+ try:
+ with open(infile, 'r') as rsdf:
+ data = rsdf.read()
+ except IOError, e:
+ self.fail(str(e))
if re.search(r"<title>404 - Not Found</title>", data) is None:
data = binascii.unhexlify(''.join(data.split()))
@@ -48,4 +53,4 @@ class RSDF(Container):
decryptedUrl = link.replace('CCF: ', '')
self.urls.append(decryptedUrl)
- self.log.debug("%s: adding package %s with %d links" % (self.__name__,pyfile.package().name,len(links)))
+ self.logDebug("Adding package %s with %d links" % (pyfile.package().name, len(self.urls)))
diff --git a/module/plugins/crypter/BitshareComFolder.py b/module/plugins/crypter/BitshareComFolder.py
index 2afe990df..c70a849b6 100644
--- a/module/plugins/crypter/BitshareComFolder.py
+++ b/module/plugins/crypter/BitshareComFolder.py
@@ -1,32 +1,24 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class BitshareComFolder(SimpleCrypter):
- __name__ = "BitshareComFolder"
- __version__ = "0.01"
- __type__ = "crypter"
+ __name__ = "BitshareComFolder"
+ __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"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __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>'
+
- LINK_PATTERN = r'<a href="(http://bitshare.com/files/.+)">.+</a></td>'
- TITLE_PATTERN = r'View public folder "(?P<title>.+)"</h1>'
+getInfo = create_getInfo(BitshareComFolder)
diff --git a/module/plugins/crypter/C1neonCom.py b/module/plugins/crypter/C1neonCom.py
index fc1188a11..bc58fbf1c 100644
--- a/module/plugins/crypter/C1neonCom.py
+++ b/module/plugins/crypter/C1neonCom.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class C1neonCom(DeadCrypter):
- __name__ = "C1neonCom"
+ __name__ = "C1neonCom"
+ __type__ = "crypter"
__version__ = "0.05"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?c1neon.com/.*?'
+ __pattern__ = r'http://(?:www\.)?c1neon\.com/.+'
+ __config__ = []
__description__ = """C1neon.com decrypter plugin"""
- __author_name__ = "godofdream"
- __author_mail__ = "soilfiction@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("godofdream", "soilfiction@gmail.com")]
+
+
+getInfo = create_getInfo(C1neonCom)
diff --git a/module/plugins/crypter/ChipDe.py b/module/plugins/crypter/ChipDe.py
index f59903170..133e5a005 100644
--- a/module/plugins/crypter/ChipDe.py
+++ b/module/plugins/crypter/ChipDe.py
@@ -5,23 +5,25 @@ from module.plugins.Crypter import Crypter
class ChipDe(Crypter):
- __name__ = "ChipDe"
- __version__ = "0.1"
- __type__ = "crypter"
+ __name__ = "ChipDe"
+ __type__ = "crypter"
+ __version__ = "0.10"
- __pattern__ = r'http://(?:www\.)?chip.de/video/.*\.html'
+ __pattern__ = r'http://(?:www\.)?chip\.de/video/.+\.html'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Chip.de decrypter plugin"""
- __author_name__ = "4Christopher"
- __author_mail__ = "4Christopher@gmx.de"
+ __license__ = "GPLv3"
+ __authors__ = [("4Christopher", "4Christopher@gmx.de")]
def decrypt(self, pyfile):
self.html = self.load(pyfile.url)
try:
- f = re.search(r'"(http://video.chip.de/\d+?/.*)"', self.html)
+ f = re.search(r'"(http://video\.chip\.de/.+)"', self.html)
except:
- self.fail('Failed to find the URL')
+ self.fail(_("Failed to find the URL"))
else:
self.urls = [f.group(1)]
- self.logDebug('The file URL is %s' % self.urls[0])
+ self.logDebug("The file URL is %s" % self.urls[0])
diff --git a/module/plugins/crypter/CloudzillaToFolder.py b/module/plugins/crypter/CloudzillaToFolder.py
new file mode 100644
index 000000000..c156d4de4
--- /dev/null
+++ b/module/plugins/crypter/CloudzillaToFolder.py
@@ -0,0 +1,43 @@
+# -*- 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.01"
+
+ __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")
+
+
+ def getLinks(self):
+ return [urljoin("http://www.cloudzilla.to", link) for link in super(CloudzillaToFolder, self).getLinks()]
+
+
+getInfo = create_getInfo(CloudzillaToFolder)
diff --git a/module/plugins/crypter/CrockoComFolder.py b/module/plugins/crypter/CrockoComFolder.py
index 8215e23c4..57bb339ff 100644
--- a/module/plugins/crypter/CrockoComFolder.py
+++ b/module/plugins/crypter/CrockoComFolder.py
@@ -1,17 +1,23 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class CrockoComFolder(SimpleCrypter):
- __name__ = "CrockoComFolder"
+ __name__ = "CrockoComFolder"
+ __type__ = "crypter"
__version__ = "0.01"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?crocko.com/f/.*'
+ __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"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
index 331ddd5c8..2cf4e9f62 100644
--- a/module/plugins/crypter/CryptItCom.py
+++ b/module/plugins/crypter/CryptItCom.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class CryptItCom(DeadCrypter):
- __name__ = "CryptItCom"
+ __name__ = "CryptItCom"
+ __type__ = "crypter"
__version__ = "0.11"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?crypt-it\.com/(s|e|d|c)/[\w]+'
+ __pattern__ = r'http://(?:www\.)?crypt-it\.com/(s|e|d|c)/\w+'
+ __config__ = []
__description__ = """Crypt-it.com decrypter plugin"""
- __author_name__ = "jeix"
- __author_mail__ = "jeix@hasnomail.de"
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de")]
+
+
+getInfo = create_getInfo(CryptItCom)
diff --git a/module/plugins/crypter/CzshareComFolder.py b/module/plugins/crypter/CzshareComFolder.py
index b305575a2..5623a4093 100644
--- a/module/plugins/crypter/CzshareComFolder.py
+++ b/module/plugins/crypter/CzshareComFolder.py
@@ -5,15 +5,18 @@ from module.plugins.Crypter import Crypter
class CzshareComFolder(Crypter):
- __name__ = "CzshareComFolder"
- __version__ = "0.2"
- __type__ = "crypter"
+ __name__ = "CzshareComFolder"
+ __type__ = "crypter"
+ __version__ = "0.20"
- __pattern__ = r'http://(?:www\.)?(czshare|sdilej)\.(com|cz)/folders/.*'
+ __pattern__ = r'http://(?:www\.)?(czshare|sdilej)\.(com|cz)/folders/.+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Czshare.com folder decrypter plugin, now Sdilej.cz"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
FOLDER_PATTERN = r'<tr class="subdirectory">\s*<td>\s*<table>(.*?)</table>'
LINK_PATTERN = r'<td class="col2"><a href="([^"]+)">info</a></td>'
@@ -22,10 +25,8 @@ class CzshareComFolder(Crypter):
def decrypt(self, pyfile):
html = self.load(pyfile.url)
- m = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
+ m = re.search(self.FOLDER_PATTERN, html, re.S)
if m is None:
- self.fail("Parse error (FOLDER)")
+ self.error(_("FOLDER_PATTERN not found"))
self.urls.extend(re.findall(self.LINK_PATTERN, m.group(1)))
- if not self.urls:
- self.fail('Could not extract any links')
diff --git a/module/plugins/crypter/DDLMusicOrg.py b/module/plugins/crypter/DDLMusicOrg.py
index c80ec471e..55181e9ad 100644
--- a/module/plugins/crypter/DDLMusicOrg.py
+++ b/module/plugins/crypter/DDLMusicOrg.py
@@ -8,27 +8,30 @@ from module.plugins.Crypter import Crypter
class DDLMusicOrg(Crypter):
- __name__ = "DDLMusicOrg"
- __version__ = "0.3"
- __type__ = "crypter"
+ __name__ = "DDLMusicOrg"
+ __type__ = "crypter"
+ __version__ = "0.30"
__pattern__ = r'http://(?:www\.)?ddl-music\.org/captcha/ddlm_cr\d\.php\?\d+\?\d+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Ddl-music.org decrypter plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __license__ = "GPLv3"
+ __authors__ = [("mkaay", "mkaay@mkaay.de")]
def setup(self):
self.multiDL = False
+
def decrypt(self, pyfile):
- html = self.req.load(pyfile.url, cookies=True)
+ html = self.load(pyfile.url, cookies=True)
if re.search(r"Wer dies nicht rechnen kann", html) is not None:
self.offline()
- math = re.search(r"(\d+) ([\+-]) (\d+) =\s+<inp", self.html)
+ math = re.search(r"(\d+) ([+-]) (\d+) =\s+<inp", self.html)
id = re.search(r"name=\"id\" value=\"(\d+)\"", self.html).group(1)
linknr = re.search(r"name=\"linknr\" value=\"(\d+)\"", self.html).group(1)
@@ -38,7 +41,7 @@ class DDLMusicOrg(Crypter):
else:
solve = int(math.group(1)) - int(math.group(3))
sleep(3)
- htmlwithlink = self.req.load(pyfile.url, cookies=True,
+ htmlwithlink = self.load(pyfile.url, cookies=True,
post={"calc%s" % linknr: solve, "send%s" % linknr: "Send", "id": id,
"linknr": linknr})
m = re.search(r"<form id=\"ff\" action=\"(.*?)\" method=\"post\">", htmlwithlink)
diff --git a/module/plugins/crypter/DailymotionBatch.py b/module/plugins/crypter/DailymotionBatch.py
index c86c966d8..8d4cb64df 100644
--- a/module/plugins/crypter/DailymotionBatch.py
+++ b/module/plugins/crypter/DailymotionBatch.py
@@ -1,22 +1,8 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+import re
from urlparse import urljoin
-import re
from module.common.json_layer import json_loads
from module.plugins.Crypter import Crypter
@@ -24,15 +10,17 @@ from module.utils import save_join
class DailymotionBatch(Crypter):
- __name__ = "DailymotionBatch"
+ __name__ = "DailymotionBatch"
+ __type__ = "crypter"
__version__ = "0.01"
- __type__ = "crypter"
__pattern__ = r'https?://(?:www\.)?dailymotion\.com/((playlists/)?(?P<TYPE>playlist|user)/)?(?P<ID>[\w^_]+)(?(TYPE)|#)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Dailymotion.com channel & playlist decrypter"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
def api_response(self, ref, req=None):
@@ -40,6 +28,7 @@ class DailymotionBatch(Crypter):
page = self.load(url, get=req)
return json_loads(page)
+
def getPlaylistInfo(self, id):
ref = "playlist/" + id
req = {"fields": "name,owner.screenname"}
@@ -52,6 +41,7 @@ class DailymotionBatch(Crypter):
owner = playlist['owner.screenname']
return name, owner
+
def _getPlaylists(self, user_id, page=1):
ref = "user/%s/playlists" % user_id
req = {"fields": "id", "page": page, "limit": 100}
@@ -67,9 +57,11 @@ class DailymotionBatch(Crypter):
for item in self._getPlaylists(user_id, page + 1):
yield item
+
def getPlaylists(self, user_id):
return [(id,) + self.getPlaylistInfo(id) for id in self._getPlaylists(user_id)]
+
def _getVideos(self, id, page=1):
ref = "playlist/%s/videos" % id
req = {"fields": "url", "page": page, "limit": 100}
@@ -85,13 +77,15 @@ class DailymotionBatch(Crypter):
for item in self._getVideos(id, page + 1):
yield item
+
def getVideos(self, playlist_id):
return list(self._getVideos(playlist_id))[::-1]
+
def decrypt(self, pyfile):
m = re.match(self.__pattern__, pyfile.url)
- m_id = m.group("ID")
- m_type = m.group("TYPE")
+ m_id = m.group('ID')
+ m_type = m.group('TYPE')
if m_type == "playlist":
self.logDebug("Url recognized as Playlist")
@@ -103,7 +97,7 @@ class DailymotionBatch(Crypter):
self.logDebug("%s playlist\s found on channel \"%s\"" % (len(playlists), m_id))
if not playlists:
- self.fail("No playlist available")
+ self.fail(_("No playlist available"))
for p_id, p_name, p_owner in playlists:
p_videos = self.getVideos(p_id)
diff --git a/module/plugins/crypter/DataHuFolder.py b/module/plugins/crypter/DataHuFolder.py
index 553936b1a..a5602d6c6 100644
--- a/module/plugins/crypter/DataHuFolder.py
+++ b/module/plugins/crypter/DataHuFolder.py
@@ -1,57 +1,43 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class DataHuFolder(SimpleCrypter):
- __name__ = "DataHuFolder"
- __version__ = "0.03"
- __type__ = "crypter"
+ __name__ = "DataHuFolder"
+ __type__ = "crypter"
+ __version__ = "0.06"
- __pattern__ = r'http://(?:www\.)?data.hu/dir/\w+'
+ __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"""
- __author_name__ = ("crash", "stickell")
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("crash", None),
+ ("stickell", "l.stickell@yahoo.it")]
- LINK_PATTERN = r"<a href='(http://data\.hu/get/.+)' target='_blank'>\1</a>"
- TITLE_PATTERN = ur'<title>(?P<title>.+) Let\xf6lt\xe9se</title>'
+ LINK_PATTERN = r'<a href=\'(http://data\.hu/get/.+)\' target=\'_blank\'>\1</a>'
+ NAME_PATTERN = ur'<title>(?P<N>.+) Let\xf6lt\xe9se</title>'
- def decrypt(self, pyfile):
- self.html = self.load(pyfile.url, decode=True)
+
+ def prepare(self):
+ super(DataHuFolder, self).prepare()
if u'K\xe9rlek add meg a jelsz\xf3t' in self.html: # Password protected
password = self.getPassword()
- if password is '':
- self.fail("No password specified, please set right password on Add package form and retry")
- self.logDebug('The folder is password protected', 'Using password: ' + password)
- self.html = self.load(pyfile.url, post={'mappa_pass': password}, decode=True)
- if u'Hib\xe1s jelsz\xf3' in self.html: # Wrong password
- self.fail("Incorrect password, please set right password on Add package form and retry")
+ if not password:
+ self.fail(_("Password required"))
+
+ self.logDebug("The folder is password protected', 'Using password: " + password)
- package_name, folder_name = self.getPackageNameAndFolder()
+ 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"))
- package_links = re.findall(self.LINK_PATTERN, self.html)
- self.logDebug('Package has %d links' % len(package_links))
- if package_links:
- self.packages = [(package_name, package_links, folder_name)]
- else:
- self.fail('Could not extract any links')
+getInfo = create_getInfo(DataHuFolder)
diff --git a/module/plugins/crypter/DdlstorageComFolder.py b/module/plugins/crypter/DdlstorageComFolder.py
index 4c79407e4..e02e77fda 100644
--- a/module/plugins/crypter/DdlstorageComFolder.py
+++ b/module/plugins/crypter/DdlstorageComFolder.py
@@ -1,31 +1,20 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
-class DdlstorageComFolder(SimpleCrypter):
- __name__ = "DdlstorageComFolder"
- __version__ = "0.02"
- __type__ = "crypter"
+class DdlstorageComFolder(DeadCrypter):
+ __name__ = "DdlstorageComFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
- __pattern__ = r'http://(?:www\.)?ddlstorage.com/folder/\w{10}'
+ __pattern__ = r'https?://(?:www\.)?ddlstorage\.com/folder/\w+'
+ __config__ = []
__description__ = """DDLStorage.com folder decrypter plugin"""
- __author_name__ = ("godofdream", "stickell")
- __author_mail__ = ("soilfiction@gmail.com", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("godofdream", "soilfiction@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
- LINK_PATTERN = r'<a class="sub_title" style="text-decoration:none;" href="(http://www.ddlstorage.com/.*)">'
+
+getInfo = create_getInfo(DdlstorageComFolder)
diff --git a/module/plugins/crypter/DepositfilesComFolder.py b/module/plugins/crypter/DepositfilesComFolder.py
index bb08b627b..147f093c3 100644
--- a/module/plugins/crypter/DepositfilesComFolder.py
+++ b/module/plugins/crypter/DepositfilesComFolder.py
@@ -1,17 +1,23 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class DepositfilesComFolder(SimpleCrypter):
- __name__ = "DepositfilesComFolder"
+ __name__ = "DepositfilesComFolder"
+ __type__ = "crypter"
__version__ = "0.01"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?depositfiles.com/folders/\w+'
+ __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"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
index 405893560..0729c8cb6 100644
--- a/module/plugins/crypter/Dereferer.py
+++ b/module/plugins/crypter/Dereferer.py
@@ -1,38 +1,17 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
+from module.plugins.internal.SimpleDereferer import SimpleDereferer
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+class Dereferer(SimpleDereferer):
+ __name__ = "Dereferer"
+ __type__ = "crypter"
+ __version__ = "0.11"
-import re
-import urllib
-
-from module.plugins.Crypter import Crypter
-
-
-class Dereferer(Crypter):
- __name__ = "Dereferer"
- __version__ = "0.1"
- __type__ = "crypter"
-
- __pattern__ = r'https?://([^/]+)/.*?(?P<url>(ht|f)tps?(://|%3A%2F%2F).*)'
+ __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"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
-
- def decrypt(self, pyfile):
- link = re.match(self.__pattern__, pyfile.url).group('url')
- self.urls = [urllib.unquote(link).rstrip('+')]
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
diff --git a/module/plugins/crypter/DevhostStFolder.py b/module/plugins/crypter/DevhostStFolder.py
new file mode 100644
index 000000000..5ac9d4faf
--- /dev/null
+++ b/module/plugins/crypter/DevhostStFolder.py
@@ -0,0 +1,61 @@
+# -*- 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, create_getInfo
+
+
+class DevhostStFolder(SimpleCrypter):
+ __name__ = "DevhostStFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
+ __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}
+
+
+ def getLinks(self):
+ return [urljoin("http://d-h.st", link) for link in re.findall(self.LINK_PATTERN, self.html)]
+
+
+getInfo = create_getInfo(DevhostStFolder)
diff --git a/module/plugins/crypter/DlProtectCom.py b/module/plugins/crypter/DlProtectCom.py
index 6bd6bc5b5..a99ed0be9 100644
--- a/module/plugins/crypter/DlProtectCom.py
+++ b/module/plugins/crypter/DlProtectCom.py
@@ -1,37 +1,26 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
import re
from base64 import urlsafe_b64encode
from time import time
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class DlProtectCom(SimpleCrypter):
- __name__ = "DlProtectCom"
+ __name__ = "DlProtectCom"
+ __type__ = "crypter"
__version__ = "0.01"
- __type__ = "crypter"
__pattern__ = r'http://(?:www\.)?dl-protect\.com/((en|fr)/)?(?P<ID>\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"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
OFFLINE_PATTERN = r'>Unfortunately, the link you are looking for is not found'
@@ -41,7 +30,7 @@ class DlProtectCom(SimpleCrypter):
if not re.match(r"http://(?:www\.)?dl-protect\.com", self.req.http.lastEffectiveURL):
return [self.req.http.lastEffectiveURL]
- #id = re.match(self.__pattern__, self.pyfile.url).group("ID")
+ #id = re.match(self.__pattern__, self.pyfile.url).group('ID')
key = re.search(r'name="id_key" value="(.+?)"', self.html).group(1)
post_req = {"id_key": key, "submitform": ""}
@@ -70,7 +59,10 @@ class DlProtectCom(SimpleCrypter):
for errmsg in (">The password is incorrect", ">The security code is incorrect"):
if errmsg in self.html:
- self.fail(errmsg[1:])
+ self.fail(_(errmsg[1:]))
pattern = r'<a href="([^/].+?)" target="_blank">'
return re.findall(pattern, self.html)
+
+
+getInfo = create_getInfo(DlProtectCom)
diff --git a/module/plugins/crypter/DontKnowMe.py b/module/plugins/crypter/DontKnowMe.py
index dac385e7c..d656cde4c 100644
--- a/module/plugins/crypter/DontKnowMe.py
+++ b/module/plugins/crypter/DontKnowMe.py
@@ -1,25 +1,17 @@
# -*- coding: utf-8 -*-
-import re
-import urllib
+from module.plugins.internal.SimpleDereferer import SimpleDereferer
-from module.plugins.Crypter import Crypter
+class DontKnowMe(SimpleDereferer):
+ __name__ = "DontKnowMe"
+ __type__ = "crypter"
+ __version__ = "0.11"
-class DontKnowMe(Crypter):
- __name__ = "DontKnowMe"
- __version__ = "0.1"
- __type__ = "crypter"
-
- __pattern__ = r'http://(?:www\.)?dontknow.me/at/\?.+$'
+ __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"""
- __author_name__ = "selaux"
- __author_mail__ = None
-
- LINK_PATTERN = r'http://dontknow.me/at/\?(.+)$'
-
-
- def decrypt(self, pyfile):
- link = re.findall(self.LINK_PATTERN, pyfile.url)[0]
- self.urls = [urllib.unquote(link)]
+ __license__ = "GPLv3"
+ __authors__ = [("selaux", "")]
diff --git a/module/plugins/crypter/DuckCryptInfo.py b/module/plugins/crypter/DuckCryptInfo.py
index 7e13a62f0..07cc5cdc4 100644
--- a/module/plugins/crypter/DuckCryptInfo.py
+++ b/module/plugins/crypter/DuckCryptInfo.py
@@ -1,57 +1,59 @@
# -*- coding: utf-8 -*-
import re
-from module.lib.BeautifulSoup import BeautifulSoup
+
+from BeautifulSoup import BeautifulSoup
+
from module.plugins.Crypter import Crypter
class DuckCryptInfo(Crypter):
- __name__ = "DuckCryptInfo"
+ __name__ = "DuckCryptInfo"
+ __type__ = "crypter"
__version__ = "0.02"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?duckcrypt.info/(folder|wait|link)/(\w+)/?(\w*)'
+ __pattern__ = r'http://(?:www\.)?duckcrypt\.info/(folder|wait|link)/(\w+)/?(\w*)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """DuckCrypt.info decrypter plugin"""
- __author_name__ = "godofdream"
- __author_mail__ = "soilfiction@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("godofdream", "soilfiction@gmail.com")]
+
TIMER_PATTERN = r'<span id="timer">(.*)</span>'
def decrypt(self, pyfile):
url = pyfile.url
- # seems we don't need to wait
- #src = self.req.load(str(url))
- #m = re.search(self.TIMER_PATTERN, src)
- #if m:
- # self.logDebug("Sleeping for" % m.group(1))
- # self.setWait(int(m.group(1)) ,False)
+
m = re.match(self.__pattern__, url)
if m is None:
- self.fail('Weird error in link')
+ self.fail(_("Weird error in link"))
if str(m.group(1)) == "link":
self.handleLink(url)
else:
self.handleFolder(m)
+
def handleFolder(self, m):
- src = self.load("http://duckcrypt.info/ajax/auth.php?hash=" + str(m.group(2)))
- m = re.match(self.__pattern__, src)
+ html = self.load("http://duckcrypt.info/ajax/auth.php?hash=" + str(m.group(2)))
+ m = re.match(self.__pattern__, html)
self.logDebug("Redirectet to " + str(m.group(0)))
- src = self.load(str(m.group(0)))
- soup = BeautifulSoup(src)
+ html = self.load(str(m.group(0)))
+ soup = BeautifulSoup(html)
cryptlinks = soup.findAll("div", attrs={"class": "folderbox"})
self.logDebug("Redirectet to " + str(cryptlinks))
if not cryptlinks:
- self.fail('no links m - (Plugin out of date?)')
+ self.error(_("No link found"))
for clink in cryptlinks:
if clink.find("a"):
self.handleLink(clink.find("a")['href'])
+
def handleLink(self, url):
- src = self.load(url)
- soup = BeautifulSoup(src)
- self.urls = [soup.find("iframe")["src"]]
+ html = self.load(url)
+ soup = BeautifulSoup(html)
+ self.urls = [soup.find("iframe")['src']]
if not self.urls:
- self.logDebug('no links m - (Plugin out of date?)')
+ self.logInfo(_("No link found"))
diff --git a/module/plugins/crypter/DuploadOrgFolder.py b/module/plugins/crypter/DuploadOrgFolder.py
index f2b8da2bd..066fbe3d7 100644
--- a/module/plugins/crypter/DuploadOrgFolder.py
+++ b/module/plugins/crypter/DuploadOrgFolder.py
@@ -1,31 +1,19 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
-class DuploadOrgFolder(SimpleCrypter):
- __name__ = "DuploadOrgFolder"
- __version__ = "0.01"
- __type__ = "crypter"
+class DuploadOrgFolder(DeadCrypter):
+ __name__ = "DuploadOrgFolder"
+ __type__ = "crypter"
+ __version__ = "0.02"
- __pattern__ = r'http://(?:www\.)?dupload\.org/folder/\d+/'
+ __pattern__ = r'http://(?:www\.)?dupload\.org/folder/\d+'
+ __config__ = []
__description__ = """Dupload.org folder decrypter plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
- LINK_PATTERN = r'<td style="[^"]+"><a href="(http://[^"]+)" target="_blank">[^<]+</a></td>'
+
+getInfo = create_getInfo(DuploadOrgFolder)
diff --git a/module/plugins/crypter/EasybytezComFolder.py b/module/plugins/crypter/EasybytezComFolder.py
index 7c78b7946..04f9b853b 100644
--- a/module/plugins/crypter/EasybytezComFolder.py
+++ b/module/plugins/crypter/EasybytezComFolder.py
@@ -1,34 +1,25 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
-
-
-class EasybytezComFolder(SimpleCrypter):
- __name__ = "EasybytezComFolder"
- __version__ = "0.06"
- __type__ = "crypter"
-
- __pattern__ = r'http://(?:www\.)?easybytez\.com/users/(?P<ID>\d+/\d+)'
-
- __description__ = """Easybytez.com decrypter plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- URL_REPLACEMENTS = [(__pattern__, r"http://www.easybytez.com/users/\g<ID>?per_page=10000")]
-
- LINK_PATTERN = r'<td><a href="(http://www\.easybytez\.com/\w+)" target="_blank">.+(?:</a>)?</td>'
- TITLE_PATTERN = r'<Title>Files of \d+: (?P<title>.+) folder</Title>'
+
+from module.plugins.internal.XFSCrypter import XFSCrypter, create_getInfo
+
+
+class EasybytezComFolder(XFSCrypter):
+ __name__ = "EasybytezComFolder"
+ __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")]
+
+
+ HOSTER_DOMAIN = "easybytez.com"
+
+ LOGIN_ACCOUNT = True
+
+
+getInfo = create_getInfo(EasybytezComFolder)
diff --git a/module/plugins/crypter/EmbeduploadCom.py b/module/plugins/crypter/EmbeduploadCom.py
index 052f5ca84..be3181793 100644
--- a/module/plugins/crypter/EmbeduploadCom.py
+++ b/module/plugins/crypter/EmbeduploadCom.py
@@ -6,17 +6,20 @@ from module.network.HTTPRequest import BadHeader
class EmbeduploadCom(Crypter):
- __name__ = "EmbeduploadCom"
+ __name__ = "EmbeduploadCom"
+ __type__ = "crypter"
__version__ = "0.02"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?embedupload.com/\?d=.*'
- __config__ = [("preferedHoster", "str", "Prefered hoster list (bar-separated) ", "embedupload"),
- ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")]
+ __pattern__ = r'http://(?:www\.)?embedupload\.com/\?d=.+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True),
+ ("preferedHoster", "str", "Prefered hoster list (bar-separated)", "embedupload"),
+ ("ignoredHoster", "str", "Ignored hoster list (bar-separated)", "")]
__description__ = """EmbedUpload.com decrypter plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
LINK_PATTERN = r'<div id="([^"]+)"[^>]*>\s*<a href="([^"]+)" target="_blank" (?:class="DownloadNow"|style="color:red")>'
@@ -29,26 +32,28 @@ class EmbeduploadCom(Crypter):
if m:
prefered_set = set(self.getConfig("preferedHoster").split('|'))
prefered_set = map(lambda s: s.lower().split('.')[0], prefered_set)
- print "PF", prefered_set
+
+ self.logDebug("PF: %s" % prefered_set)
+
tmp_links.extend([x[1] for x in m if x[0] in prefered_set])
self.urls = self.getLocation(tmp_links)
if not self.urls:
ignored_set = set(self.getConfig("ignoredHoster").split('|'))
ignored_set = map(lambda s: s.lower().split('.')[0], ignored_set)
- print "IG", ignored_set
+
+ self.logDebug("IG: %s" % ignored_set)
+
tmp_links.extend([x[1] for x in m if x[0] not in ignored_set])
self.urls = self.getLocation(tmp_links)
- if not self.urls:
- self.fail('Could not extract any links')
def getLocation(self, tmp_links):
new_links = []
for link in tmp_links:
try:
header = self.load(link, just_header=True)
- if "location" in header:
+ if 'location' in header:
new_links.append(header['location'])
except BadHeader:
pass
diff --git a/module/plugins/crypter/FilebeerInfoFolder.py b/module/plugins/crypter/FilebeerInfoFolder.py
index 7a7528066..a3c7ee74c 100644
--- a/module/plugins/crypter/FilebeerInfoFolder.py
+++ b/module/plugins/crypter/FilebeerInfoFolder.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class FilebeerInfoFolder(DeadCrypter):
- __name__ = "FilebeerInfoFolder"
+ __name__ = "FilebeerInfoFolder"
+ __type__ = "crypter"
__version__ = "0.02"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?filebeer\.info/(\d+~f).*'
+ __pattern__ = r'http://(?:www\.)?filebeer\.info/\d*~f\w+'
+ __config__ = []
__description__ = """Filebeer.info folder decrypter plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+getInfo = create_getInfo(FilebeerInfoFolder)
diff --git a/module/plugins/crypter/FilecloudIoFolder.py b/module/plugins/crypter/FilecloudIoFolder.py
index d3df7c469..83cce352d 100644
--- a/module/plugins/crypter/FilecloudIoFolder.py
+++ b/module/plugins/crypter/FilecloudIoFolder.py
@@ -1,32 +1,24 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FilecloudIoFolder(SimpleCrypter):
- __name__ = "FilecloudIoFolder"
- __version__ = "0.01"
- __type__ = "crypter"
+ __name__ = "FilecloudIoFolder"
+ __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"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ LINK_PATTERN = r'href="(http://filecloud\.io/\w+)" title'
+ NAME_PATTERN = r'>(?P<N>.+?) - filecloud\.io<'
+
- LINK_PATTERN = r'href="(http://filecloud.io/\w+)" title'
- TITLE_PATTERN = r'>(?P<title>.+?) - filecloud.io<'
+getInfo = create_getInfo(FilecloudIoFolder)
diff --git a/module/plugins/crypter/FilecryptCc.py b/module/plugins/crypter/FilecryptCc.py
new file mode 100644
index 000000000..087f377ff
--- /dev/null
+++ b/module/plugins/crypter/FilecryptCc.py
@@ -0,0 +1,170 @@
+# -*- coding: utf-8 -*-
+
+import base64
+import binascii
+import re
+
+from Crypto.Cipher import AES
+from urlparse import urljoin
+
+from module.plugins.Crypter import Crypter
+
+
+class FilecryptCc(Crypter):
+ __name__ = "FilecryptCc"
+ __type__ = "crypter"
+ __version__ = "0.07"
+
+ __pattern__ = r'https?://(?:www\.)?filecrypt\.cc/Container/\w+'
+
+ __description__ = """Filecrypt.cc decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("zapp-brannigan", "")]
+
+
+ # 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"))
+
+ if not self.pyfile.package().password:
+ self.fail(_("Please enter the password in package section and try again"))
+
+ self.html = self.load(self.pyfile.url, post={"password": self.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:
+ self.logDebug("No captcha found")
+ self.siteWithLinks = self.html
+
+ if "recaptcha_image" 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))
+
+ # Decode crypted
+ crypted = base64.standard_b64decode(crypted)
+
+ # Decrypt
+ Key = key
+ IV = key
+ obj = AES.new(Key, AES.MODE_CBC, IV)
+ text = obj.decrypt(crypted)
+
+ # Extract links
+ links = filter(lambda x: x != "",
+ text.replace("\x00", "").replace("\r", "").split("\n"))
+
+ return links
diff --git a/module/plugins/crypter/FilefactoryComFolder.py b/module/plugins/crypter/FilefactoryComFolder.py
index ce20ee6eb..26e28acbd 100644
--- a/module/plugins/crypter/FilefactoryComFolder.py
+++ b/module/plugins/crypter/FilefactoryComFolder.py
@@ -1,25 +1,31 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FilefactoryComFolder(SimpleCrypter):
- __name__ = "FilefactoryComFolder"
- __version__ = "0.2"
- __type__ = "crypter"
+ __name__ = "FilefactoryComFolder"
+ __type__ = "crypter"
+ __version__ = "0.31"
__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"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
LINK_PATTERN = r'<td><a href="([^"]+)">'
- TITLE_PATTERN = r'<h1>Files in <span>(?P<title>.+)</span></h1>'
- PAGES_PATTERN = r'data-paginator-totalPages="(?P<pages>\d+)"'
+ NAME_PATTERN = r'<h1>Files in <span>(?P<N>.+)</span></h1>'
+ PAGES_PATTERN = r'data-paginator-totalPages="(\d+)"'
- SH_COOKIES = [('.filefactory.com', 'locale', 'en_US.utf8')]
+ COOKIES = [("filefactory.com", "locale", "en_US.utf8")]
def loadPage(self, page_n):
return self.load(self.pyfile.url, get={'page': page_n})
+
+
+getInfo = create_getInfo(FilefactoryComFolder)
diff --git a/module/plugins/crypter/FilerNetFolder.py b/module/plugins/crypter/FilerNetFolder.py
index 77e7409e9..00db173bb 100644
--- a/module/plugins/crypter/FilerNetFolder.py
+++ b/module/plugins/crypter/FilerNetFolder.py
@@ -1,22 +1,29 @@
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FilerNetFolder(SimpleCrypter):
- __name__ = "FilerNetFolder"
- __version__ = "0.3"
- __type__ = "crypter"
+ __name__ = "FilerNetFolder"
+ __type__ = "crypter"
+ __version__ = "0.41"
__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"""
- __author_name_ = ("nath_schwarz", "stickell")
- __author_mail_ = ("nathan.notwhite@gmail.com", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
+
LINK_PATTERN = r'href="(/get/\w{16})">(?!<)'
- TITLE_PATTERN = r'<h3>(?P<title>.+) - <small'
+ NAME_PATTERN = r'<h3>(?P<N>.+?) - <small'
def getLinks(self):
return ['http://filer.net%s' % link for link in re.findall(self.LINK_PATTERN, self.html)]
+
+
+getInfo = create_getInfo(FilerNetFolder)
diff --git a/module/plugins/crypter/FileserveComFolder.py b/module/plugins/crypter/FileserveComFolder.py
index 4a0d5a416..e6b35fd36 100644
--- a/module/plugins/crypter/FileserveComFolder.py
+++ b/module/plugins/crypter/FileserveComFolder.py
@@ -6,15 +6,18 @@ from module.plugins.Crypter import Crypter
class FileserveComFolder(Crypter):
- __name__ = "FileserveComFolder"
+ __name__ = "FileserveComFolder"
+ __type__ = "crypter"
__version__ = "0.11"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?fileserve.com/list/\w+'
+ __pattern__ = r'http://(?:www\.)?fileserve\.com/list/\w+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """FileServe.com folder decrypter plugin"""
- __author_name__ = "fionnc"
- __author_mail__ = "fionnc@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("fionnc", "fionnc@gmail.com")]
+
FOLDER_PATTERN = r'<table class="file_list">(.*?)</table>'
LINK_PATTERN = r'<a href="([^"]+)" class="sheet_icon wbold">'
@@ -25,13 +28,11 @@ class FileserveComFolder(Crypter):
new_links = []
- folder = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
+ folder = re.search(self.FOLDER_PATTERN, html, re.S)
if folder is None:
- self.fail("Parse error (FOLDER)")
+ self.error(_("FOLDER_PATTERN not found"))
new_links.extend(re.findall(self.LINK_PATTERN, folder.group(1)))
if new_links:
self.urls = [map(lambda s: "http://fileserve.com%s" % s, new_links)]
- else:
- self.fail('Could not extract any links')
diff --git a/module/plugins/crypter/FilesonicComFolder.py b/module/plugins/crypter/FilesonicComFolder.py
new file mode 100644
index 000000000..d58516986
--- /dev/null
+++ b/module/plugins/crypter/FilesonicComFolder.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
+
+
+class FilesonicComFolder(DeadCrypter):
+ __name__ = "FilesonicComFolder"
+ __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(FilesonicComFolder)
diff --git a/module/plugins/crypter/FilestubeCom.py b/module/plugins/crypter/FilestubeCom.py
index 7576319e0..16ebdda37 100644
--- a/module/plugins/crypter/FilestubeCom.py
+++ b/module/plugins/crypter/FilestubeCom.py
@@ -1,32 +1,24 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FilestubeCom(SimpleCrypter):
- __name__ = "FilestubeCom"
- __version__ = "0.03"
- __type__ = "crypter"
+ __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"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
LINK_PATTERN = r'<a class=\"file-link-main(?: noref)?\" [^>]* href=\"(http://[^\"]+)'
- TITLE_PATTERN = r'<h1\s*> (?P<title>.+) download\s*</h1>'
+ 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
index 2491c1322..76530c589 100644
--- a/module/plugins/crypter/FiletramCom.py
+++ b/module/plugins/crypter/FiletramCom.py
@@ -1,32 +1,25 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FiletramCom(SimpleCrypter):
- __name__ = "FiletramCom"
- __version__ = "0.01"
- __type__ = "crypter"
+ __name__ = "FiletramCom"
+ __type__ = "crypter"
+ __version__ = "0.03"
- __pattern__ = r'http://(?:www\.)?filetram.com/[^/]+/.+'
+ __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"""
- __author_name__ = ("igel", "stickell")
- __author_mail__ = ("igelkun@myopera.com", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("igel", "igelkun@myopera.com"),
+ ("stickell", "l.stickell@yahoo.it")]
+
LINK_PATTERN = r'\s+(http://.+)'
- TITLE_PATTERN = r'<title>(?P<title>[^<]+) - Free Download[^<]*</title>'
+ NAME_PATTERN = r'<title>(?P<N>.+?) - Free Download'
+
+
+getInfo = create_getInfo(FiletramCom)
diff --git a/module/plugins/crypter/FiredriveComFolder.py b/module/plugins/crypter/FiredriveComFolder.py
index c0db299b0..7d3a357fd 100644
--- a/module/plugins/crypter/FiredriveComFolder.py
+++ b/module/plugins/crypter/FiredriveComFolder.py
@@ -1,42 +1,19 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-import re
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
-
-class FiredriveComFolder(SimpleCrypter):
- __name__ = "FiredriveComFolder"
- __version__ = "0.01"
- __type__ = "crypter"
+class FiredriveComFolder(DeadCrypter):
+ __name__ = "FiredriveComFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
__pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/share/.+'
+ __config__ = []
__description__ = """Firedrive.com folder decrypter plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
-
- LINK_PATTERN = r'<div class="pf_item pf_(file|folder).+?public=\'(.+?)\''
- TITLE_PATTERN = r'>Shared Folder "(?P<title>.+)" | Firedrive<'
- OFFLINE_PATTERN = r'class="sad_face_image"|>No such page here.<'
- TEMP_OFFLINE_PATTERN = r'>(File Temporarily Unavailable|Server Error. Try again later)'
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- def getLinks(self):
- return map(lambda x: "http://www.firedrive.com/%s/%s" %
- ("share" if x[0] == "folder" else "file", x[1]),
- re.findall(self.LINK_PATTERN, self.html))
+getInfo = create_getInfo(FiredriveComFolder)
diff --git a/module/plugins/crypter/FourChanOrg.py b/module/plugins/crypter/FourChanOrg.py
index a911c64d6..d6c5c86cc 100644
--- a/module/plugins/crypter/FourChanOrg.py
+++ b/module/plugins/crypter/FourChanOrg.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Based on 4chandl by Roland Beermann
-# https://gist.github.com/enkore/3492599
+#
+# Based on 4chandl by Roland Beermann (https://gist.github.com/enkore/3492599)
import re
@@ -8,15 +8,17 @@ from module.plugins.Crypter import Crypter
class FourChanOrg(Crypter):
- __name__ = "FourChanOrg"
- __version__ = "0.3"
- __type__ = "crypter"
+ __name__ = "FourChanOrg"
+ __type__ = "crypter"
+ __version__ = "0.30"
- __pattern__ = r'http://(?:www\.)?boards\.4chan.org/\w+/res/(\d+)'
+ __pattern__ = r'http://(?:www\.)?boards\.4chan\.org/\w+/res/(\d+)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """4chan.org folder decrypter plugin"""
- __author_name__ = None
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = []
def decrypt(self, pyfile):
diff --git a/module/plugins/crypter/FreakhareComFolder.py b/module/plugins/crypter/FreakhareComFolder.py
index ddc05199b..7c1b7de2b 100644
--- a/module/plugins/crypter/FreakhareComFolder.py
+++ b/module/plugins/crypter/FreakhareComFolder.py
@@ -1,38 +1,27 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FreakhareComFolder(SimpleCrypter):
- __name__ = "FreakhareComFolder"
- __version__ = "0.01"
- __type__ = "crypter"
+ __name__ = "FreakhareComFolder"
+ __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"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
- LINK_PATTERN = r'<a href="(http://freakshare.com/files/[^"]+)" target="_blank">'
- TITLE_PATTERN = r'Folder:</b> (?P<title>.+)'
- PAGES_PATTERN = r'Pages: +(?P<pages>\d+)'
+
+ 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):
@@ -47,3 +36,6 @@ class FreakhareComFolder(SimpleCrypter):
'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
index a6fb78d8e..c33c9ff64 100644
--- a/module/plugins/crypter/FreetexthostCom.py
+++ b/module/plugins/crypter/FreetexthostCom.py
@@ -1,39 +1,30 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FreetexthostCom(SimpleCrypter):
- __name__ = "FreetexthostCom"
+ __name__ = "FreetexthostCom"
+ __type__ = "crypter"
__version__ = "0.01"
- __type__ = "crypter"
__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"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __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.DOTALL)
+ m = re.search(r'<div id="contentsinner">\s*(.+)<div class="viewcount">', self.html, re.S)
if m is None:
- self.fail('Unable to extract links | Plugin may be out-of-date')
+ 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/FshareVnFolder.py b/module/plugins/crypter/FshareVnFolder.py
index 9f5162125..474364e40 100644
--- a/module/plugins/crypter/FshareVnFolder.py
+++ b/module/plugins/crypter/FshareVnFolder.py
@@ -1,17 +1,23 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FshareVnFolder(SimpleCrypter):
- __name__ = "FshareVnFolder"
+ __name__ = "FshareVnFolder"
+ __type__ = "crypter"
__version__ = "0.01"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?fshare.vn/folder/.*'
+ __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"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
new file mode 100644
index 000000000..102bc32b5
--- /dev/null
+++ b/module/plugins/crypter/Go4UpCom.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from urlparse import urljoin
+
+from module.plugins.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:
+ continue
+
+ return links
+
+
+getInfo = create_getInfo(Go4UpCom)
diff --git a/module/plugins/crypter/GooGl.py b/module/plugins/crypter/GooGl.py
index 52bf93ed3..d548a3375 100644
--- a/module/plugins/crypter/GooGl.py
+++ b/module/plugins/crypter/GooGl.py
@@ -1,43 +1,32 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
from module.plugins.Crypter import Crypter
from module.common.json_layer import json_loads
class GooGl(Crypter):
- __name__ = "GooGl"
+ __name__ = "GooGl"
+ __type__ = "crypter"
__version__ = "0.01"
- __type__ = "crypter"
__pattern__ = r'https?://(?:www\.)?goo\.gl/\w+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Goo.gl decrypter plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
API_URL = "https://www.googleapis.com/urlshortener/v1/url"
def decrypt(self, pyfile):
rep = self.load(self.API_URL, get={'shortUrl': pyfile.url})
- self.logDebug('JSON data: ' + rep)
+ self.logDebug("JSON data: " + rep)
rep = json_loads(rep)
if 'longUrl' in rep:
self.urls = [rep['longUrl']]
else:
- self.fail('Unable to expand shortened link')
+ self.fail(_("Unable to expand shortened link"))
diff --git a/module/plugins/crypter/HoerbuchIn.py b/module/plugins/crypter/HoerbuchIn.py
index 88fc57244..a347e4232 100644
--- a/module/plugins/crypter/HoerbuchIn.py
+++ b/module/plugins/crypter/HoerbuchIn.py
@@ -2,20 +2,25 @@
import re
+from BeautifulSoup import BeautifulSoup, BeautifulStoneSoup
+
from module.plugins.Crypter import Crypter
-from module.lib.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup
class HoerbuchIn(Crypter):
- __name__ = "HoerbuchIn"
- __version__ = "0.6"
- __type__ = "crypter"
+ __name__ = "HoerbuchIn"
+ __type__ = "crypter"
+ __version__ = "0.60"
- __pattern__ = r'http://(?:www\.)?hoerbuch\.in/(wp/horbucher/\d+/.+/|tp/out.php\?.+|protection/folder_\d+\.html)'
+ __pattern__ = r'http://(?:www\.)?hoerbuch\.in/(wp/horbucher/\d+/.+/|tp/out\.php\?.+|protection/folder_\d+\.html)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Hoerbuch.in decrypter plugin"""
- __author_name__ = ("spoob", "mkaay")
- __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de")
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org"),
+ ("mkaay", "mkaay@mkaay.de")]
+
article = re.compile("http://(?:www\.)?hoerbuch\.in/wp/horbucher/\d+/.+/")
protection = re.compile("http://(?:www\.)?hoerbuch\.in/protection/folder_\d+.html")
@@ -25,8 +30,8 @@ class HoerbuchIn(Crypter):
self.pyfile = pyfile
if self.article.match(pyfile.url):
- src = self.load(pyfile.url)
- soup = BeautifulSoup(src, convertEntities=BeautifulStoneSoup.HTML_ENTITIES)
+ html = self.load(pyfile.url)
+ soup = BeautifulSoup(html, convertEntities=BeautifulStoneSoup.HTML_ENTITIES)
abookname = soup.find("a", attrs={"rel": "bookmark"}).text
for a in soup.findAll("a", attrs={"href": self.protection}):
@@ -37,18 +42,19 @@ class HoerbuchIn(Crypter):
else:
self.urls = self.decryptFolder(pyfile.url)
+
def decryptFolder(self, url):
m = self.protection.search(url)
if m is None:
- self.fail("Bad URL")
+ self.fail(_("Bad URL"))
url = m.group(0)
self.pyfile.url = url
- src = self.req.load(url, post={"viewed": "adpg"})
+ html = self.load(url, post={"viewed": "adpg"})
links = []
pattern = re.compile("http://www\.hoerbuch\.in/protection/(\w+)/(.*?)\"")
- for hoster, lid in pattern.findall(src):
+ for hoster, lid in pattern.findall(html):
self.req.lastURL = url
self.load("http://www.hoerbuch.in/protection/%s/%s" % (hoster, lid))
links.append(self.req.lastEffectiveURL)
diff --git a/module/plugins/crypter/HotfileComFolder.py b/module/plugins/crypter/HotfileComFolder.py
new file mode 100644
index 000000000..4f40587ad
--- /dev/null
+++ b/module/plugins/crypter/HotfileComFolder.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
+
+
+class HotfileComFolder(DeadCrypter):
+ __name__ = "HotfileComFolder"
+ __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(HotfileComFolder)
diff --git a/module/plugins/crypter/HotfileFolderCom.py b/module/plugins/crypter/HotfileFolderCom.py
deleted file mode 100644
index 433dc9755..000000000
--- a/module/plugins/crypter/HotfileFolderCom.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-
-from module.plugins.Crypter import Crypter
-
-
-class HotfileFolderCom(Crypter):
- __name__ = "HotfileFolderCom"
- __version__ = "0.1"
- __type__ = "crypter"
-
- __pattern__ = r'http://(?:www\.)?hotfile.com/list/\w+/\w+'
-
- __description__ = """Hotfile.com folder decrypter plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
-
-
- def decrypt(self, pyfile):
- html = self.load(pyfile.url)
-
- name = re.findall(
- r'<img src="/i/folder.gif" width="23" height="14" style="margin-bottom: -2px;" />([^<]+)', html,
- re.MULTILINE)[0].replace("/", "")
- new_links = re.findall(r'href="(http://(www.)?hotfile\.com/dl/\d+/[0-9a-zA-Z]+[^"]+)', html)
-
- new_links = [x[0] for x in new_links]
-
- self.packages = [(name, new_links, name)]
diff --git a/module/plugins/crypter/ILoadTo.py b/module/plugins/crypter/ILoadTo.py
index e003e07f4..f3415706d 100644
--- a/module/plugins/crypter/ILoadTo.py
+++ b/module/plugins/crypter/ILoadTo.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class ILoadTo(DeadCrypter):
- __name__ = "ILoadTo"
+ __name__ = "ILoadTo"
+ __type__ = "crypter"
__version__ = "0.11"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?iload\.to/go/\d+-[\w\.-]+/'
+ __pattern__ = r'http://(?:www\.)?iload\.to/go/\d+-[\w.-]+/'
+ __config__ = []
__description__ = """Iload.to decrypter plugin"""
- __author_name__ = "hzpz"
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = [("hzpz", None)]
+
+
+getInfo = create_getInfo(ILoadTo)
diff --git a/module/plugins/crypter/ImgurComAlbum.py b/module/plugins/crypter/ImgurComAlbum.py
index 394673586..6c074f5f1 100644
--- a/module/plugins/crypter/ImgurComAlbum.py
+++ b/module/plugins/crypter/ImgurComAlbum.py
@@ -1,24 +1,30 @@
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
from module.utils import uniqify
class ImgurComAlbum(SimpleCrypter):
- __name__ = "ImgurComAlbum"
- __version__ = "0.4"
- __type__ = "crypter"
+ __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"""
- __author_name_ = "nath_schwarz"
- __author_mail_ = "nathan.notwhite@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com")]
- TITLE_PATTERN = r'(?P<title>.+) - Imgur'
+
+ 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/JunocloudMeFolder.py b/module/plugins/crypter/JunocloudMeFolder.py
new file mode 100644
index 000000000..990f25902
--- /dev/null
+++ b/module/plugins/crypter/JunocloudMeFolder.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSCrypter import XFSCrypter, create_getInfo
+
+
+class JunocloudMeFolder(XFSCrypter):
+ __name__ = "JunocloudMeFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
+ __pattern__ = r'http://(?:www\.)?junocloud\.me/folders/(?P<ID>\d+/\w+)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
+ __description__ = """Junocloud.me folder decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("guidobelix", "guidobelix@hotmail.it")]
+
+
+ HOSTER_DOMAIN = "junocloud.me"
+
+
+getInfo = create_getInfo(JunocloudMeFolder)
diff --git a/module/plugins/crypter/LetitbitNetFolder.py b/module/plugins/crypter/LetitbitNetFolder.py
index adb2918a6..56ecbc7f8 100644
--- a/module/plugins/crypter/LetitbitNetFolder.py
+++ b/module/plugins/crypter/LetitbitNetFolder.py
@@ -5,15 +5,19 @@ from module.plugins.Crypter import Crypter
class LetitbitNetFolder(Crypter):
- __name__ = "LetitbitNetFolder"
- __version__ = "0.1"
- __type__ = "crypter"
+ __name__ = "LetitbitNetFolder"
+ __type__ = "crypter"
+ __version__ = "0.10"
- __pattern__ = r'http://(?:www\.)?letitbit.net/folder/\w+'
+ __pattern__ = r'http://(?:www\.)?letitbit\.net/folder/\w+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Letitbit.net folder decrypter plugin"""
- __author_name__ = ("DHMH", "z00nx")
- __author_mail__ = ("webmaster@pcProfil.de", "z00nx0@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("DHMH", "webmaster@pcProfil.de"),
+ ("z00nx", "z00nx0@gmail.com")]
+
FOLDER_PATTERN = r'<table>(.*)</table>'
LINK_PATTERN = r'<a href="([^"]+)" target="_blank">'
@@ -22,11 +26,8 @@ class LetitbitNetFolder(Crypter):
def decrypt(self, pyfile):
html = self.load(pyfile.url)
- folder = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
+ folder = re.search(self.FOLDER_PATTERN, html, re.S)
if folder is None:
- self.fail("Parse error (FOLDER)")
+ self.error(_("FOLDER_PATTERN not found"))
self.urls.extend(re.findall(self.LINK_PATTERN, folder.group(0)))
-
- if not self.urls:
- self.fail('Could not extract any links')
diff --git a/module/plugins/crypter/LinkCryptWs.py b/module/plugins/crypter/LinkCryptWs.py
new file mode 100644
index 000000000..835a549b2
--- /dev/null
+++ b/module/plugins/crypter/LinkCryptWs.py
@@ -0,0 +1,327 @@
+# -*- coding: utf-8 -*-
+
+import base64
+import binascii
+import re
+
+import pycurl
+
+from Crypto.Cipher import AES
+
+from module.plugins.Crypter import Crypter
+from module.utils import html_unescape
+
+
+class LinkCryptWs(Crypter):
+ __name__ = "LinkCryptWs"
+ __type__ = "crypter"
+ __version__ = "0.07"
+
+ __pattern__ = r'http://(?:www\.)?linkcrypt\.ws/(dir|container)/(?P<ID>\w+)'
+
+ __description__ = """LinkCrypt.ws decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("kagenoshin", "kagenoshin[AT]gmx[DOT]ch"),
+ ("glukgluk", None),
+ ("Gummibaer", None)]
+
+
+ CRYPTED_KEY = "crypted"
+ JK_KEY = "jk"
+
+
+ def setup(self):
+ self.captcha = False
+ self.links = []
+ self.sources = ['cnl', 'web', 'dlc', 'rsdf', 'ccf']
+
+
+ def prepare(self):
+ # Init
+ self.fileid = re.match(self.__pattern__, self.pyfile.url).group('ID')
+
+ self.req.cj.setCookie("linkcrypt.ws", "language", "en")
+
+ # Request package
+ self.req.http.c.setopt(pycurl.USERAGENT, "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko") #: better chance to not get those key-captchas
+ self.html = self.load(self.pyfile.url)
+
+
+ def decrypt(self, pyfile):
+ if not self.js:
+ self.fail(_("Missing JS Engine"))
+
+ self.prepare()
+
+ if not self.isOnline():
+ self.offline()
+
+ if self.isKeyCaptchaProtected():
+ self.retry(4, 30, _("Can't handle Key-Captcha"))
+
+ if self.isCaptchaProtected():
+ self.captcha = True
+ self.unlockCaptchaProtection()
+ self.handleCaptchaErrors()
+
+ # Check for protection
+ if self.isPasswordProtected():
+ self.unlockPasswordProtection()
+ self.handleErrors()
+
+ # get unrar password
+ self.getunrarpw()
+
+ # Get package name and folder
+ package_name, folder_name = self.getPackageInfo()
+
+ #get the container definitions from script section
+ self.get_container_html()
+
+ # Extract package links
+ for type in self.sources:
+ links = self.handleLinkSource(type)
+
+ if links:
+ self.links.extend(links)
+ break
+
+ if self.links:
+ self.packages = [(package_name, self.links, folder_name)]
+
+
+ def isOnline(self):
+ if "<title>Linkcrypt.ws // Error 404</title>" in self.html:
+ self.logDebug("folder doesen't exist anymore")
+ return False
+ else:
+ return True
+
+
+ def isPasswordProtected(self):
+ if "Authorizing" in self.html:
+ self.logDebug("Links are password protected")
+ return True
+ else:
+ return False
+
+
+ def isCaptchaProtected(self):
+ if 'id="captcha">' in self.html:
+ self.logDebug("Links are captcha protected")
+ return True
+ else:
+ return False
+
+
+ def isKeyCaptchaProtected(self):
+ if re.search(r'Key[ -]', self.html, re.I):
+ return True
+ else:
+ return False
+
+
+ def unlockPasswordProtection(self):
+ password = self.getPassword()
+
+ if password:
+ self.logDebug("Submitting password [%s] for protected links" % password)
+ self.html = self.load(self.pyfile.url, post={"password": password, 'x': "0", 'y': "0"})
+ else:
+ self.fail(_("Folder is password protected"))
+
+
+ def unlockCaptchaProtection(self):
+ captcha_url = re.search(r'<form.*?id\s*?=\s*?"captcha"[^>]*?>.*?<\s*?input.*?src="([^"]*?)"', self.html, re.I | re.S).group(1)
+ captcha_code = self.decryptCaptcha(captcha_url, forceUser=True, imgtype="gif", result_type='positional')
+
+ self.html = self.load(self.pyfile.url, post={"x": captcha_code[0], "y": captcha_code[1]})
+
+
+ def getPackageInfo(self):
+ name = self.pyfile.package().name
+ folder = self.pyfile.package().folder
+
+ self.logDebug("Defaulting to pyfile name [%s] and folder [%s] for package" % (name, folder))
+
+ return name, folder
+
+
+ def getunrarpw(self):
+ sitein = self.html
+ indexi = sitein.find("|source|") + 8
+ indexe = sitein.find("|",indexi)
+
+ unrarpw = sitein[indexi:indexe]
+
+ if not (unrarpw == "Password" or "Dateipasswort") :
+ self.logDebug("File password set to: [%s]"% unrarpw)
+ self.pyfile.package().password = unrarpw
+
+
+ def handleErrors(self):
+ if self.isPasswordProtected():
+ self.fail(_("Incorrect password"))
+
+
+ def handleCaptchaErrors(self):
+ if self.captcha:
+ if "Your choice was wrong!" in self.html:
+ self.invalidCaptcha()
+ self.retry()
+ else:
+ self.correctCaptcha()
+
+
+ def handleLinkSource(self, type):
+ if type == 'cnl':
+ return self.handleCNL2()
+
+ elif type == 'web':
+ return self.handleWebLinks()
+
+ elif type in ('rsdf', 'ccf', 'dlc'):
+ return self.handleContainer(type)
+
+ else:
+ self.fail(_("Unknown source type: %s") % type) #@TODO: Replace with self.error in 0.4.10
+
+
+ def handleWebLinks(self):
+ self.logDebug("Search for Web links ")
+
+ package_links = []
+ pattern = r'<form action="http://linkcrypt.ws/out.html"[^>]*?>.*?<input[^>]*?value="([^"]*?)"[^>]*?name="file"'
+ ids = re.findall(pattern, self.html, re.I | re.S)
+
+ self.logDebug("Decrypting %d Web links" % len(ids))
+
+ for idx, weblink_id in enumerate(ids):
+ try:
+ self.logDebug("Decrypting Web link %d, %s" % (idx + 1, weblink_id))
+
+ res = self.load("http://linkcrypt.ws/out.html", post = {'file':weblink_id})
+
+ indexs = res.find("window.location =") + 19
+ indexe = res.find('"', indexs)
+
+ link2 = res[indexs:indexe]
+
+ self.logDebug(link2)
+
+ link2 = html_unescape(link2)
+ package_links.append(link2)
+
+ except Exception, detail:
+ self.logDebug("Error decrypting Web link %s, %s" % (weblink_id, detail))
+
+ return package_links
+
+
+ def get_container_html(self):
+ self.container_html = []
+
+ script = re.search(r'<div.*?id="ad_cont".*?<script.*?javascrip[^>]*?>(.*?)</script', self.html, re.I | re.S)
+
+ if script:
+ container_html_text = script.group(1)
+ container_html_text.strip()
+ self.container_html = container_html_text.splitlines()
+
+
+ def handle_javascript(self, line):
+ return self.js.eval(line.replace('{}))',"{}).replace('document.open();document.write','').replace(';document.close();',''))"))
+
+
+ def handleContainer(self, type):
+ package_links = []
+ type = type.lower()
+
+ self.logDebug('Search for %s Container links' % type.upper())
+
+ if not type.isalnum(): # check to prevent broken re-pattern (cnl2,rsdf,ccf,dlc,web are all alpha-numeric)
+ self.fail(_("Unknown container type: %s") % type) #@TODO: Replace with self.error in 0.4.10
+
+ for line in self.container_html:
+ if type in line:
+ jseval = self.handle_javascript(line)
+ clink = re.search(r'href=["\']([^"\']*?)["\']',jseval,re.I)
+
+ if not clink:
+ continue
+
+ self.logDebug("clink avaible")
+
+ package_name, folder_name = self.getPackageInfo()
+ self.logDebug("Added package with name %s.%s and container link %s" %( package_name, type, clink.group(1)))
+ self.core.api.uploadContainer( "%s.%s" %(package_name, type), self.load(clink.group(1)))
+ return "Found it"
+
+ return package_links
+
+
+ def handleCNL2(self):
+ self.logDebug("Search for CNL links")
+
+ package_links = []
+ cnl_line = None
+
+ for line in self.container_html:
+ if "cnl" in line:
+ cnl_line = line
+ break
+
+ if cnl_line:
+ self.logDebug("cnl_line gefunden")
+
+ try:
+ cnl_section = self.handle_javascript(cnl_line)
+ (vcrypted, vjk) = self._getCipherParams(cnl_section)
+ for (crypted, jk) in zip(vcrypted, vjk):
+ package_links.extend(self._getLinks(crypted, jk))
+ except:
+ self.logError(_("Unable to decrypt CNL links (JS Error) try to get over links"))
+ return self.handleWebLinks()
+
+ return package_links
+
+
+ def _getCipherParams(self, cnl_section):
+ # Get jk
+ jk_re = r'<INPUT.*?NAME="%s".*?VALUE="(.*?)"' % LinkCryptWs.JK_KEY
+ vjk = re.findall(jk_re, cnl_section)
+
+ # Get crypted
+ crypted_re = r'<INPUT.*?NAME="%s".*?VALUE="(.*?)"' % LinkCryptWs.CRYPTED_KEY
+ vcrypted = re.findall(crypted_re, cnl_section)
+
+ # 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)
+ key = binascii.unhexlify(jreturn)
+
+ self.logDebug("JsEngine returns value [%s]" % jreturn)
+
+ # Decode crypted
+ crypted = base64.standard_b64decode(crypted)
+
+ # Decrypt
+ Key = key
+ IV = key
+ obj = AES.new(Key, AES.MODE_CBC, IV)
+ text = obj.decrypt(crypted)
+
+ # Extract links
+ text = text.replace("\x00", "").replace("\r", "")
+ links = text.split("\n")
+ links = filter(lambda x: x != "", links)
+
+ # Log and return
+ self.logDebug("Package has %d links" % len(links))
+
+ return links
diff --git a/module/plugins/crypter/LinkSaveIn.py b/module/plugins/crypter/LinkSaveIn.py
index 6e024c766..e96d0438e 100644
--- a/module/plugins/crypter/LinkSaveIn.py
+++ b/module/plugins/crypter/LinkSaveIn.py
@@ -1,228 +1,22 @@
# -*- coding: utf-8 -*-
-#
-# v2.01 - hagg
-# * cnl2 and web links are skipped if JS is not available (instead of failing the package)
-# * only best available link source is used (priority: cnl2>rsdf>ccf>dlc>web
-#
+from module.plugins.internal.SimpleDereferer import SimpleDereferer
-import base64
-import binascii
-import re
-from Crypto.Cipher import AES
-from module.plugins.Crypter import Crypter
-from module.unescape import unescape
+class LinkSaveIn(SimpleDereferer):
+ __name__ = "LinkSaveIn"
+ __type__ = "crypter"
+ __version__ = "2.03"
-
-class LinkSaveIn(Crypter):
- __name__ = "LinkSaveIn"
- __version__ = "2.01"
- __type__ = "crypter"
-
- __pattern__ = r'http://(?:www\.)?linksave.in/(?P<id>\w+)$'
+ __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"""
- __author_name__ = "fragonib"
- __author_mail__ = "fragonib[AT]yahoo[DOT]es"
-
- # Constants
- _JK_KEY_ = "jk"
- _CRYPTED_KEY_ = "crypted"
- HOSTER_NAME = "linksave.in"
-
-
- def setup(self):
- self.html = None
- self.fileid = None
- self.captcha = False
- self.package = None
- self.preferred_sources = ["cnl2", "rsdf", "ccf", "dlc", "web"]
-
- def decrypt(self, pyfile):
- # Init
- self.package = pyfile.package()
- self.fileid = re.match(self.__pattern__, pyfile.url).group('id')
- self.req.cj.setCookie(self.HOSTER_NAME, "Linksave_Language", "english")
-
- # Request package
- self.html = self.load(pyfile.url)
- 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 type_ in self.preferred_sources:
- package_links.extend(self.handleLinkSource(type_))
- 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)]
- else:
- self.fail('Could not extract any links')
-
- def isOnline(self):
- if "<big>Error 404 - Folder not found!</big>" in self.html:
- self.logDebug("File not found")
- return False
- return True
-
- def isPasswordProtected(self):
- if re.search(r'''<input.*?type="password"''', self.html):
- self.logDebug("Links are password protected")
- return True
-
- def isCaptchaProtected(self):
- if "<b>Captcha:</b>" 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)
- post = {"id": self.fileid, "besucherpasswort": password, 'login': 'submit'}
- self.html = self.load(self.pyfile.url, post=post)
-
- def unlockCaptchaProtection(self):
- captcha_hash = re.search(r'name="hash" value="([^"]+)', self.html).group(1)
- captcha_url = re.search(r'src=".(/captcha/cap.php\?hsh=[^"]+)', self.html).group(1)
- captcha_code = self.decryptCaptcha("http://linksave.in" + captcha_url, forceUser=True)
- self.html = self.load(self.pyfile.url, post={"id": self.fileid, "hash": captcha_hash, "code": captcha_code})
-
- def getPackageInfo(self):
- name = self.pyfile.package().name
- folder = self.pyfile.package().folder
- self.logDebug("Defaulting to pyfile name [%s] and folder [%s] for package" % (name, folder))
- return name, folder
-
- def handleErrors(self):
- if "The visitorpassword you have entered is wrong" in self.html:
- self.logDebug("Incorrect password, please set right password on 'Edit package' form and retry")
- self.fail("Incorrect password, please set right password on 'Edit package' form and retry")
-
- if self.captcha:
- if "Wrong code. Please retry" in self.html:
- self.logDebug("Invalid captcha, retrying")
- self.invalidCaptcha()
- self.retry()
- else:
- self.correctCaptcha()
-
- def handleLinkSource(self, type_):
- if type_ == "cnl2":
- return self.handleCNL2()
- elif type_ in ("rsdf", "ccf", "dlc"):
- return self.handleContainer(type_)
- elif type_ == "web":
- return self.handleWebLinks()
- else:
- self.fail('unknown source type "%s" (this is probably a bug)' % type_)
-
- def handleWebLinks(self):
- package_links = []
- self.logDebug("Search for Web links")
- if not self.js:
- self.logDebug("no JS -> skip Web links")
- else:
- #@TODO: Gather paginated web links
- pattern = r'<a href="http://linksave\.in/(\w{43})"'
- ids = re.findall(pattern, self.html)
- self.logDebug("Decrypting %d Web links" % len(ids))
- for i, weblink_id in enumerate(ids):
- try:
- webLink = "http://linksave.in/%s" % weblink_id
- self.logDebug("Decrypting Web link %d, %s" % (i + 1, webLink))
- fwLink = "http://linksave.in/fw-%s" % weblink_id
- response = self.load(fwLink)
- jscode = re.findall(r'<script type="text/javascript">(.*)</script>', response)[-1]
- jseval = self.js.eval("document = { write: function(e) { return e; } }; %s" % jscode)
- dlLink = re.search(r'http://linksave\.in/dl-\w+', jseval).group(0)
- self.logDebug("JsEngine returns value [%s] for redirection link" % dlLink)
- response = self.load(dlLink)
- link = unescape(re.search(r'<iframe src="(.+?)"', response).group(1))
- package_links.append(link)
- except Exception, detail:
- self.logDebug("Error decrypting Web link %s, %s" % (webLink, detail))
- return package_links
-
- def handleContainer(self, type_):
- package_links = []
- type_ = type_.lower()
- self.logDebug('Seach for %s Container links' % type_.upper())
- if not type_.isalnum(): # check to prevent broken re-pattern (cnl2,rsdf,ccf,dlc,web are all alpha-numeric)
- self.fail('unknown container type "%s" (this is probably a bug)' % type_)
- pattern = r"\('%s_link'\).href=unescape\('(.*?\.%s)'\)" % (type_, type_)
- containersLinks = re.findall(pattern, self.html)
- self.logDebug("Found %d %s Container links" % (len(containersLinks), type_.upper()))
- for containerLink in containersLinks:
- link = "http://linksave.in/%s" % unescape(containerLink)
- package_links.append(link)
- return package_links
-
- def handleCNL2(self):
- package_links = []
- self.logDebug("Search for CNL2 links")
- if not self.js:
- self.logDebug("no JS -> skip CNL2 links")
- elif 'cnl2_load' in self.html:
- try:
- (vcrypted, vjk) = self._getCipherParams()
- for (crypted, jk) in zip(vcrypted, vjk):
- package_links.extend(self._getLinks(crypted, jk))
- except:
- self.fail("Unable to decrypt CNL2 links")
- return package_links
-
- def _getCipherParams(self):
- # Get jk
- jk_re = r'<INPUT.*?NAME="%s".*?VALUE="(.*?)"' % LinkSaveIn._JK_KEY_
- vjk = re.findall(jk_re, self.html)
-
- # Get crypted
- crypted_re = r'<INPUT.*?NAME="%s".*?VALUE="(.*?)"' % LinkSaveIn._CRYPTED_KEY_
- vcrypted = re.findall(crypted_re, self.html)
-
- # 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)
-
- # Decode crypted
- crypted = base64.standard_b64decode(crypted)
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- # Decrypt
- Key = key
- IV = key
- obj = AES.new(Key, AES.MODE_CBC, IV)
- text = obj.decrypt(crypted)
- # Extract links
- text = text.replace("\x00", "").replace("\r", "")
- links = text.split("\n")
- links = filter(lambda x: x != "", links)
+ COOKIES = [("linksave.in", "Linksave_Language", "english")]
- # Log and return
- self.logDebug("Package has %d links" % len(links))
- return links
+ OFFLINE_PATTERN = r'>(Error )?404 -'
diff --git a/module/plugins/crypter/LinkdecrypterCom.py b/module/plugins/crypter/LinkdecrypterCom.py
index 2671c19c6..91318eadf 100644
--- a/module/plugins/crypter/LinkdecrypterCom.py
+++ b/module/plugins/crypter/LinkdecrypterCom.py
@@ -1,34 +1,23 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from module.plugins.Crypter import Crypter
class LinkdecrypterCom(Crypter):
- __name__ = "LinkdecrypterCom"
+ __name__ = "LinkdecrypterCom"
+ __type__ = "crypter"
__version__ = "0.27"
- __type__ = "crypter"
- __pattern__ = None
+ __pattern__ = r'^unmatchable$'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Linkdecrypter.com"""
- __author_name__ = ("zoidberg", "flowlee")
- __author_mail__ = ("zoidberg@mujmail.cz", "")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("flowlee", None)]
+
TEXTAREA_PATTERN = r'<textarea name="links" wrap="off" readonly="1" class="caja_des">(.+)</textarea>'
PASSWORD_PATTERN = r'<input type="text" name="password"'
@@ -37,16 +26,13 @@ class LinkdecrypterCom(Crypter):
def decrypt(self, pyfile):
-
self.passwords = self.getPassword().splitlines()
# API not working anymore
self.urls = self.decryptHTML()
- if not self.urls:
- self.fail('Could not extract any links')
- def decryptAPI(self):
+ def decryptAPI(self):
get_dict = {"t": "link", "url": self.pyfile.url, "lcache": "1"}
self.html = self.load('http://linkdecrypter.com/api', get=get_dict)
if self.html.startswith('http://'):
@@ -58,21 +44,21 @@ class LinkdecrypterCom(Crypter):
if self.html.startswith('http://'):
return self.html.splitlines()
- self.logError('API', self.html)
+ self.logError("API", self.html)
if self.html == 'INTERRUPTION(PASSWORD)':
- self.fail("No or incorrect password")
+ self.fail(_("No or incorrect password"))
return None
- def decryptHTML(self):
+ def decryptHTML(self):
retries = 5
post_dict = {"link_cache": "on", "pro_links": self.pyfile.url, "modo_links": "text"}
self.html = self.load('http://linkdecrypter.com/', post=post_dict, cookies=True, decode=True)
while self.passwords or retries:
- m = re.search(self.TEXTAREA_PATTERN, self.html, flags=re.DOTALL)
+ m = re.search(self.TEXTAREA_PATTERN, self.html, flags=re.S)
if m:
return [x for x in m.group(1).splitlines() if '[LINK-ERROR]' not in x]
@@ -83,7 +69,7 @@ class LinkdecrypterCom(Crypter):
m = re.search(r"<p><i><b>([^<]+)</b></i></p>", self.html)
msg = m.group(1) if m else ""
- self.logInfo("Captcha protected link", result_type, msg)
+ self.logInfo(_("Captcha protected link"), result_type, msg)
captcha = self.decryptCaptcha(captcha_url, result_type=result_type)
if result_type == "positional":
@@ -94,10 +80,10 @@ class LinkdecrypterCom(Crypter):
elif self.PASSWORD_PATTERN in self.html:
if self.passwords:
password = self.passwords.pop(0)
- self.logInfo("Password protected link, trying " + password)
+ self.logInfo(_("Password protected link, trying ") + password)
self.html = self.load('http://linkdecrypter.com/', post={'password': password}, decode=True)
else:
- self.fail("No or incorrect password")
+ self.fail(_("No or incorrect password"))
else:
retries -= 1
diff --git a/module/plugins/crypter/LixIn.py b/module/plugins/crypter/LixIn.py
index a39173903..d899d58c7 100644
--- a/module/plugins/crypter/LixIn.py
+++ b/module/plugins/crypter/LixIn.py
@@ -6,19 +6,22 @@ from module.plugins.Crypter import Crypter
class LixIn(Crypter):
- __name__ = "LixIn"
+ __name__ = "LixIn"
+ __type__ = "crypter"
__version__ = "0.22"
- __type__ = "crypter"
- __pattern__ = r'http://(www.)?lix.in/(?P<id>.*)'
+ __pattern__ = r'http://(?:www\.)?lix\.in/(?P<ID>.+)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Lix.in decrypter plugin"""
- __author_name__ = "spoob"
- __author_mail__ = "spoob@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org")]
- CAPTCHA_PATTERN = r'<img src="(?P<image>captcha_img.php\?.*?)"'
- SUBMIT_PATTERN = r"value='continue.*?'"
- LINK_PATTERN = r'name="ifram" src="(?P<link>.*?)"'
+
+ CAPTCHA_PATTERN = r'<img src="(captcha_img\.php\?.*?)"'
+ SUBMIT_PATTERN = r'value=\'continue.*?\''
+ LINK_PATTERN = r'name="ifram" src="(.*?)"'
def decrypt(self, pyfile):
@@ -26,34 +29,34 @@ class LixIn(Crypter):
m = re.match(self.__pattern__, url)
if m is None:
- self.fail("couldn't identify file id")
+ self.error(_("Unable to identify file ID"))
- id = m.group("id")
+ id = m.group('ID')
self.logDebug("File id is %s" % id)
- self.html = self.req.load(url, decode=True)
+ self.html = self.load(url, decode=True)
m = re.search(self.SUBMIT_PATTERN, self.html)
if m is None:
- self.fail("link doesn't seem valid")
+ self.error(_("Link doesn't seem valid"))
m = re.search(self.CAPTCHA_PATTERN, self.html)
if m:
- for _ in xrange(5):
+ for _i in xrange(5):
m = re.search(self.CAPTCHA_PATTERN, self.html)
if m:
- self.logDebug("trying captcha")
- captcharesult = self.decryptCaptcha("http://lix.in/" + m.group("image"))
- self.html = self.req.load(url, decode=True,
+ self.logDebug("Trying captcha")
+ captcharesult = self.decryptCaptcha("http://lix.in/" + m.group(1))
+ self.html = self.load(url, decode=True,
post={"capt": captcharesult, "submit": "submit", "tiny": id})
else:
- self.logDebug("no captcha/captcha solved")
+ self.logDebug("No captcha/captcha solved")
else:
- self.html = self.req.load(url, decode=True, post={"submit": "submit", "tiny": id})
+ self.html = self.load(url, decode=True, post={"submit": "submit", "tiny": id})
m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.fail("can't find destination url")
+ self.error(_("Unable to find destination url"))
else:
- self.urls = [m.group("link")]
+ self.urls = [m.group(1)]
self.logDebug("Found link %s, adding to package" % self.urls[0])
diff --git a/module/plugins/crypter/LofCc.py b/module/plugins/crypter/LofCc.py
index 91106dc51..3cac0fbf2 100644
--- a/module/plugins/crypter/LofCc.py
+++ b/module/plugins/crypter/LofCc.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class LofCc(DeadCrypter):
- __name__ = "LofCc"
+ __name__ = "LofCc"
+ __type__ = "crypter"
__version__ = "0.21"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?lof.cc/(.*)'
+ __pattern__ = r'http://(?:www\.)?lof\.cc/(.+)'
+ __config__ = []
__description__ = """Lof.cc decrypter plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __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
index 0162c111d..82c2d9719 100644
--- a/module/plugins/crypter/MBLinkInfo.py
+++ b/module/plugins/crypter/MBLinkInfo.py
@@ -1,15 +1,20 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class MBLinkInfo(DeadCrypter):
- __name__ = "MBLinkInfo"
+ __name__ = "MBLinkInfo"
+ __type__ = "crypter"
__version__ = "0.03"
- __type__ = "crypter"
__pattern__ = r'http://(?:www\.)?mblink\.info/?\?id=(\d+)'
+ __config__ = []
__description__ = """MBLink.info decrypter plugin"""
- __author_name__ = ("Gummibaer", "stickell")
- __author_mail__ = ("Gummibaer@wiki-bierkiste.de", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("Gummibaer", "Gummibaer@wiki-bierkiste.de"),
+ ("stickell", "l.stickell@yahoo.it")]
+
+
+getInfo = create_getInfo(MBLinkInfo)
diff --git a/module/plugins/crypter/MediafireComFolder.py b/module/plugins/crypter/MediafireComFolder.py
index 5dd4e555b..d1dc89518 100644
--- a/module/plugins/crypter/MediafireComFolder.py
+++ b/module/plugins/crypter/MediafireComFolder.py
@@ -7,28 +7,31 @@ from module.common.json_layer import json_loads
class MediafireComFolder(Crypter):
- __name__ = "MediafireComFolder"
+ __name__ = "MediafireComFolder"
+ __type__ = "crypter"
__version__ = "0.14"
- __type__ = "crypter"
__pattern__ = r'http://(?:www\.)?mediafire\.com/(folder/|\?sharekey=|\?\w{13}($|[/#]))'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Mediafire.com folder decrypter plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FOLDER_KEY_PATTERN = r"var afI= '(\w+)';"
- FILE_URL_PATTERN = r'<meta property="og:url" content="http://www.mediafire.com/\?(\w+)"/>'
+
+ FOLDER_KEY_PATTERN = r'var afI= \'(\w+)'
+ LINK_PATTERN = r'<meta property="og:url" content="http://www\.mediafire\.com/\?(\w+)"/>'
def decrypt(self, pyfile):
url, result = checkHTMLHeader(pyfile.url)
- self.logDebug('Location (%d): %s' % (result, url))
+ self.logDebug("Location (%d): %s" % (result, url))
if result == 0:
- # load and parse html
+ # load and parse html
html = self.load(pyfile.url)
- m = re.search(self.FILE_URL_PATTERN, html)
+ m = re.search(self.LINK_PATTERN, html)
if m:
# file page
self.urls.append("http://www.mediafire.com/file/%s" % m.group(1))
@@ -39,8 +42,10 @@ class MediafireComFolder(Crypter):
folder_key = m.group(1)
self.logDebug("FOLDER KEY: %s" % folder_key)
- json_resp = json_loads(self.load(
- "http://www.mediafire.com/api/folder/get_info.php?folder_key=%s&response_format=json&version=1" % folder_key))
+ json_resp = json_loads(self.load("http://www.mediafire.com/api/folder/get_info.php",
+ get={'folder_key' : folder_key,
+ 'response_format': "json",
+ 'version' : 1}))
#self.logInfo(json_resp)
if json_resp['response']['result'] == "Success":
for link in json_resp['response']['folder_info']['files']:
@@ -51,6 +56,3 @@ class MediafireComFolder(Crypter):
self.offline()
else:
self.urls.append(url)
-
- if not self.urls:
- self.fail('Could not extract any links')
diff --git a/module/plugins/crypter/MegaRapidCzFolder.py b/module/plugins/crypter/MegaRapidCzFolder.py
new file mode 100644
index 000000000..e7dff6c8a
--- /dev/null
+++ b/module/plugins/crypter/MegaRapidCzFolder.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
+
+
+class MegaRapidCzFolder(SimpleCrypter):
+ __name__ = "MegaRapidCzFolder"
+ __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/MegauploadComFolder.py b/module/plugins/crypter/MegauploadComFolder.py
new file mode 100644
index 000000000..08f96700d
--- /dev/null
+++ b/module/plugins/crypter/MegauploadComFolder.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
+
+
+class MegauploadComFolder(DeadCrypter):
+ __name__ = "MegauploadComFolder"
+ __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(MegauploadComFolder)
diff --git a/module/plugins/crypter/Movie2kTo.py b/module/plugins/crypter/Movie2kTo.py
index dcebf5e03..7d71950fd 100644
--- a/module/plugins/crypter/Movie2kTo.py
+++ b/module/plugins/crypter/Movie2kTo.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class Movie2kTo(DeadCrypter):
- __name__ = "Movie2kTo"
+ __name__ = "Movie2kTo"
+ __type__ = "crypter"
__version__ = "0.51"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?movie2k\.to/(.*)\.html'
+ __pattern__ = r'http://(?:www\.)?movie2k\.to/(.+)\.html'
+ __config__ = []
__description__ = """Movie2k.to decrypter plugin"""
- __author_name__ = "4Christopher"
- __author_mail__ = "4Christopher@gmx.de"
+ __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
index ab23def8d..5209ebf09 100644
--- a/module/plugins/crypter/MultiUpOrg.py
+++ b/module/plugins/crypter/MultiUpOrg.py
@@ -1,42 +1,30 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-
import re
from urlparse import urljoin
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class MultiUpOrg(SimpleCrypter):
- __name__ = "MultiUpOrg"
- __version__ = "0.01"
- __type__ = "crypter"
+ __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 crypter plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
- TITLE_PATTERN = r'<title>.*(Project|Projet|ownload|élécharger) (?P<title>.+?) (\(|- )'
+ 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")
+ 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/.*)'
@@ -48,3 +36,6 @@ class MultiUpOrg(SimpleCrypter):
self.html = self.load(miror_page)
return re.findall(pattern, self.html)
+
+
+getInfo = create_getInfo(MultiUpOrg)
diff --git a/module/plugins/crypter/MultiloadCz.py b/module/plugins/crypter/MultiloadCz.py
index 4b39872a7..fa1eb02d7 100644
--- a/module/plugins/crypter/MultiloadCz.py
+++ b/module/plugins/crypter/MultiloadCz.py
@@ -5,17 +5,20 @@ from module.plugins.Crypter import Crypter
class MultiloadCz(Crypter):
- __name__ = "MultiloadCz"
- __version__ = "0.4"
- __type__ = "crypter"
+ __name__ = "MultiloadCz"
+ __type__ = "crypter"
+ __version__ = "0.40"
- __pattern__ = r'http://(?:[^/]*\.)?multiload.cz/(stahnout|slozka)/.*'
- __config__ = [("usedHoster", "str", "Prefered hoster list (bar-separated) ", ""),
- ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")]
+ __pattern__ = r'http://(?:[^/]*\.)?multiload\.cz/(stahnout|slozka)/.+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True),
+ ("usedHoster", "str", "Prefered hoster list (bar-separated)", ""),
+ ("ignoredHoster", "str", "Ignored hoster list (bar-separated)", "")]
__description__ = """Multiload.cz decrypter plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
FOLDER_PATTERN = r'<form action="" method="get"><textarea[^>]*>([^>]*)</textarea></form>'
LINK_PATTERN = r'<p class="manager-server"><strong>([^<]+)</strong></p><p class="manager-linky"><a href="([^"]+)">'
@@ -37,6 +40,3 @@ class MultiloadCz(Crypter):
if not self.urls:
ignored_set = set(self.getConfig("ignoredHoster").split('|'))
self.urls.extend([x[1] for x in m if x[0] not in ignored_set])
-
- if not self.urls:
- self.fail('Could not extract any links')
diff --git a/module/plugins/crypter/MultiuploadCom.py b/module/plugins/crypter/MultiuploadCom.py
index f5c0e292b..347b7e5af 100644
--- a/module/plugins/crypter/MultiuploadCom.py
+++ b/module/plugins/crypter/MultiuploadCom.py
@@ -1,64 +1,19 @@
# -*- coding: utf-8 -*-
-import re
-from time import time
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
-from module.plugins.Crypter import Crypter
-from module.common.json_layer import json_loads
+class MultiuploadCom(DeadCrypter):
+ __name__ = "MultiuploadCom"
+ __type__ = "crypter"
+ __version__ = "0.02"
-class MultiuploadCom(Crypter):
- __name__ = "MultiuploadCom"
- __version__ = "0.01"
- __type__ = "crypter"
+ __pattern__ = r'http://(?:www\.)?multiupload\.(com|nl)/\w+'
+ __config__ = []
- __pattern__ = r'http://(?:www\.)?multiupload.com/(\w+)'
- __config__ = [("preferedHoster", "str", "Prefered hoster list (bar-separated) ", "multiupload"),
- ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")]
+ __description__ = """ MultiUpload.com decrypter plugin """
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- __description__ = """MultiUpload.com decrypter plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
- ML_LINK_PATTERN = r'<div id="downloadbutton_" style=""><a href="([^"]+)"'
-
-
- def decrypt(self, pyfile):
- self.html = self.load(pyfile.url)
- m = re.search(self.ML_LINK_PATTERN, self.html)
- ml_url = m.group(1) if m else None
-
- json_list = json_loads(self.load("http://multiupload.com/progress/", get={
- "d": re.match(self.__pattern__, pyfile.url).group(1),
- "r": str(int(time() * 1000))
- }))
-
- prefered_set = map(lambda s: s.lower().split('.')[0], set(self.getConfig("preferedHoster").split('|')))
-
- if ml_url and 'multiupload' in prefered_set:
- self.urls.append(ml_url)
-
- for link in json_list:
- if link['service'].lower() in prefered_set and int(link['status']) and not int(link['deleted']):
- url = self.getLocation(link['url'])
- if url:
- self.urls.append(url)
-
- if not self.urls:
- ignored_set = map(lambda s: s.lower().split('.')[0], set(self.getConfig("ignoredHoster").split('|')))
-
- if 'multiupload' not in ignored_set:
- self.urls.append(ml_url)
-
- for link in json_list:
- if link['service'].lower() not in ignored_set and int(link['status']) and not int(link['deleted']):
- url = self.getLocation(link['url'])
- if url:
- self.urls.append(url)
-
- if not self.urls:
- self.fail('Could not extract any links')
-
- def getLocation(self, url):
- header = self.load(url, just_header=True)
- return header['location'] if "location" in header else None
+getInfo = create_getInfo(MultiuploadCom)
diff --git a/module/plugins/crypter/NCryptIn.py b/module/plugins/crypter/NCryptIn.py
index 9a9d76f51..8b7214157 100644
--- a/module/plugins/crypter/NCryptIn.py
+++ b/module/plugins/crypter/NCryptIn.py
@@ -11,15 +11,19 @@ from module.plugins.internal.CaptchaService import ReCaptcha
class NCryptIn(Crypter):
- __name__ = "NCryptIn"
- __version__ = "1.32"
- __type__ = "crypter"
+ __name__ = "NCryptIn"
+ __type__ = "crypter"
+ __version__ = "1.33"
- __pattern__ = r'http://(?:www\.)?ncrypt.in/(?P<type>folder|link|frame)-([^/\?]+)'
+ __pattern__ = r'http://(?:www\.)?ncrypt\.in/(?P<TYPE>folder|link|frame)-([^/\?]+)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """NCrypt.in decrypter plugin"""
- __author_name__ = ("fragonib", "stickell")
- __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"),
+ ("stickell", "l.stickell@yahoo.it")]
+
JK_KEY = "jk"
CRYPTED_KEY = "crypted"
@@ -29,11 +33,11 @@ class NCryptIn(Crypter):
def setup(self):
self.package = None
- self.html = None
self.cleanedHtml = None
self.links_source_order = ["cnl2", "rsdf", "ccf", "dlc", "web"]
self.protection_type = None
+
def decrypt(self, pyfile):
# Init
self.package = pyfile.package()
@@ -54,7 +58,7 @@ class NCryptIn(Crypter):
if not self.isOnline():
self.offline()
- # Check for folder protection
+ # Check for folder protection
if self.isProtected():
self.html = self.unlockProtection()
self.cleanedHtml = self.removeHtmlCrap(self.html)
@@ -71,17 +75,19 @@ class NCryptIn(Crypter):
package_links = set(package_links)
# Pack and return links
- if not package_links:
- self.fail('Could not extract any links')
- self.packages = [(package_name, package_links, folder_name)]
+ if package_links:
+ self.packages = [(package_name, package_links, folder_name)]
+
def isSingleLink(self):
- link_type = re.match(self.__pattern__, self.pyfile.url).group('type')
+ link_type = re.match(self.__pattern__, self.pyfile.url).group('TYPE')
return link_type in ("link", "frame")
+
def requestFolderHome(self):
return self.load(self.pyfile.url, decode=True)
+
def removeHtmlCrap(self, content):
patterns = (r'(type="hidden".*?(name=".*?")?.*?value=".*?")',
r'display:none;">(.*?)</(div|span)>',
@@ -89,18 +95,20 @@ class NCryptIn(Crypter):
r'<table class="global">(.*?)</table>',
r'<iframe\s+style="display:none(.*?)</iframe>')
for pattern in patterns:
- rexpr = re.compile(pattern, re.DOTALL)
+ rexpr = re.compile(pattern, re.S)
content = re.sub(rexpr, "", content)
return content
+
def isOnline(self):
if "Your folder does not exist" in self.cleanedHtml:
self.logDebug("File not m")
return False
return True
+
def isProtected(self):
- form = re.search(r'<form.*?name.*?protected.*?>(.*?)</form>', self.cleanedHtml, re.DOTALL)
+ form = re.search(r'<form.*?name.*?protected.*?>(.*?)</form>', self.cleanedHtml, re.S)
if form is not None:
content = form.group(1)
for keyword in ("password", "captcha"):
@@ -110,6 +118,7 @@ class NCryptIn(Crypter):
return True
return False
+
def getPackageInfo(self):
m = re.search(self.NAME_PATTERN, self.html)
if m:
@@ -121,11 +130,11 @@ class NCryptIn(Crypter):
self.logDebug("Package info not m, defaulting to pyfile name [%s] and folder [%s]" % (name, folder))
return name, folder
- def unlockProtection(self):
+ def unlockProtection(self):
postData = {}
- form = re.search(r'<form name="protected"(.*?)</form>', self.cleanedHtml, re.DOTALL).group(1)
+ form = re.search(r'<form name="protected"(.*?)</form>', self.cleanedHtml, re.S).group(1)
# Submit package password
if "password" in form:
@@ -141,15 +150,15 @@ class NCryptIn(Crypter):
self.logDebug("Captcha resolved [%s]" % captcha)
postData['captcha'] = captcha
- # Resolve recaptcha
+ # Resolve recaptcha
if "recaptcha" in form:
self.logDebug("ReCaptcha protected")
captcha_key = re.search(r'\?k=(.*?)"', form).group(1)
self.logDebug("Resolving ReCaptcha with key [%s]" % captcha_key)
recaptcha = ReCaptcha(self)
- challenge, code = recaptcha.challenge(captcha_key)
+ challenge, response = recaptcha.challenge(captcha_key)
postData['recaptcha_challenge_field'] = challenge
- postData['recaptcha_response_field'] = code
+ postData['recaptcha_response_field'] = response
# Resolve circlecaptcha
if "circlecaptcha" in form:
@@ -164,20 +173,21 @@ class NCryptIn(Crypter):
postData['submit_protected'] = 'Continue to folder'
return self.load(self.pyfile.url, post=postData, decode=True)
+
def handleErrors(self):
if self.protection_type == "password":
if "This password is invalid!" in self.cleanedHtml:
self.logDebug("Incorrect password, please set right password on 'Edit package' form and retry")
- self.fail("Incorrect password, please set right password on 'Edit package' form and retry")
+ self.fail(_("Incorrect password, please set right password on 'Edit package' form and retry"))
if self.protection_type == "captcha":
if "The securitycheck was wrong!" in self.cleanedHtml:
- self.logDebug("Invalid captcha, retrying")
self.invalidCaptcha()
self.retry()
else:
self.correctCaptcha()
+
def handleLinkSource(self, link_source_type):
# Check for JS engine
require_js_engine = link_source_type in ("cnl2", "rsdf", "ccf", "dlc")
@@ -195,10 +205,10 @@ class NCryptIn(Crypter):
elif link_source_type == "web":
return self.handleWebLinks()
else:
- self.fail('unknown source type "%s" (this is probably a bug)' % link_source_type)
+ self.error('Unknown source type "%s" (this is probably a bug)' % link_source_type)
- def handleSingleLink(self):
+ def handleSingleLink(self):
self.logDebug("Handling Single link")
package_links = []
@@ -209,8 +219,8 @@ class NCryptIn(Crypter):
return package_links
- def handleCNL2(self):
+ def handleCNL2(self):
self.logDebug("Handling CNL2 links")
package_links = []
@@ -220,16 +230,16 @@ class NCryptIn(Crypter):
for (crypted, jk) in zip(vcrypted, vjk):
package_links.extend(self._getLinks(crypted, jk))
except:
- self.fail("Unable to decrypt CNL2 links")
+ self.fail(_("Unable to decrypt CNL2 links"))
return package_links
- def handleContainers(self):
+ def handleContainers(self):
self.logDebug("Handling Container links")
package_links = []
- pattern = r"/container/(rsdf|dlc|ccf)/([a-z0-9]+)"
+ pattern = r'/container/(rsdf|dlc|ccf)/(\w+)'
containersLinks = re.findall(pattern, self.html)
self.logDebug("Decrypting %d Container links" % len(containersLinks))
for containerLink in containersLinks:
@@ -238,10 +248,10 @@ class NCryptIn(Crypter):
return package_links
- def handleWebLinks(self):
+ def handleWebLinks(self):
self.logDebug("Handling Web links")
- pattern = r"(http://ncrypt\.in/link-.*?=)"
+ pattern = r'(http://ncrypt\.in/link-.*?=)'
links = re.findall(pattern, self.html)
package_links = []
@@ -254,6 +264,7 @@ class NCryptIn(Crypter):
return package_links
+
def decryptLink(self, link):
try:
url = link.replace("link-", "frame-")
@@ -262,8 +273,8 @@ class NCryptIn(Crypter):
except Exception, detail:
self.logDebug("Error decrypting link %s, %s" % (link, detail))
- def _getCipherParams(self):
+ def _getCipherParams(self):
pattern = r'<input.*?name="%s".*?value="(.*?)"'
# Get jk
@@ -278,6 +289,7 @@ class NCryptIn(Crypter):
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)
diff --git a/module/plugins/crypter/NetfolderIn.py b/module/plugins/crypter/NetfolderIn.py
index 4c7660ab5..62dc5c914 100644
--- a/module/plugins/crypter/NetfolderIn.py
+++ b/module/plugins/crypter/NetfolderIn.py
@@ -2,41 +2,36 @@
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class NetfolderIn(SimpleCrypter):
- __name__ = "NetfolderIn"
- __version__ = "0.6"
- __type__ = "crypter"
+ __name__ = "NetfolderIn"
+ __type__ = "crypter"
+ __version__ = "0.72"
- __pattern__ = r'http://(?:www\.)?netfolder.in/((?P<id1>\w+)/\w+|folder.php\?folder_id=(?P<id2>\w+))'
+ __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"""
- __author_name__ = ("RaNaN", "fragonib")
- __author_mail__ = ("RaNaN@pyload.org", "fragonib[AT]yahoo[DOT]es")
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("fragonib", "fragonib[AT]yahoo[DOT]es")]
- TITLE_PATTERN = r'<div class="Text">Inhalt des Ordners <span(.*)>(?P<title>.+)</span></div>'
+ NAME_PATTERN = r'<div class="Text">Inhalt des Ordners <span.*>(?P<N>.+)</span></div>'
- def decrypt(self, pyfile):
- # Request package
- self.html = self.load(pyfile.url)
- # Check for password protection
+ 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")
-
- # Get package name and folder
- (package_name, folder_name) = self.getPackageNameAndFolder()
+ self.fail(_("Incorrect password, please set right password on Add package form and retry"))
- # Get package links
- package_links = self.getLinks()
-
- # Set package
- self.packages = [(package_name, package_links, folder_name)]
def isPasswordProtected(self):
if '<input type="password" name="password"' in self.html:
@@ -44,18 +39,19 @@ class NetfolderIn(SimpleCrypter):
return True
return False
+
def submitPassword(self):
# Gather data
try:
- m = re.match(self.__pattern__, self.pyfile.url)
- id = max(m.group('id1'), m.group('id2'))
+ 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
+ # 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)
@@ -67,7 +63,11 @@ class NetfolderIn(SimpleCrypter):
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
index 2656b9374..1e280abd2 100644
--- a/module/plugins/crypter/NosvideoCom.py
+++ b/module/plugins/crypter/NosvideoCom.py
@@ -1,18 +1,24 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class NosvideoCom(SimpleCrypter):
- __name__ = "NosvideoCom"
- __version__ = "0.01"
- __type__ = "crypter"
+ __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"""
- __author_name__ = "igel"
- __author_mail__ = "igelkun@myopera.com"
+ __license__ = "GPLv3"
+ __authors__ = [("igel", "igelkun@myopera.com")]
- LINK_PATTERN = r'href="(http://(?:w{3}\.)?nosupload.com/\?d=\w+)"'
- TITLE_PATTERN = r'<[tT]itle>Watch (?P<title>.+)</[tT]itle>'
+
+ 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/OneKhDe.py b/module/plugins/crypter/OneKhDe.py
index 91c591ec1..cfb084da8 100644
--- a/module/plugins/crypter/OneKhDe.py
+++ b/module/plugins/crypter/OneKhDe.py
@@ -7,32 +7,35 @@ from module.plugins.Crypter import Crypter
class OneKhDe(Crypter):
- __name__ = "OneKhDe"
- __version__ = "0.1"
- __type__ = "crypter"
+ __name__ = "OneKhDe"
+ __type__ = "crypter"
+ __version__ = "0.10"
- __pattern__ = r'http://(?:www\.)?1kh.de/f/'
+ __pattern__ = r'http://(?:www\.)?1kh\.de/f/'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """1kh.de decrypter plugin"""
- __author_name__ = "spoob"
- __author_mail__ = "spoob@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org")]
def __init__(self, parent):
Crypter.__init__(self, parent)
self.parent = parent
- self.html = None
+
def file_exists(self):
""" returns True or False
"""
return True
+
def proceed(self, url, location):
url = self.parent.url
- self.html = self.req.load(url)
+ self.html = self.load(url)
link_ids = re.findall(r"<a id=\"DownloadLink_(\d*)\" href=\"http://1kh.de/", self.html)
for id in link_ids:
new_link = unescape(
- re.search("width=\"100%\" src=\"(.*)\"></iframe>", self.req.load("http://1kh.de/l/" + id)).group(1))
+ re.search("width=\"100%\" src=\"(.*)\"></iframe>", self.load("http://1kh.de/l/" + id)).group(1))
self.urls.append(new_link)
diff --git a/module/plugins/crypter/OronComFolder.py b/module/plugins/crypter/OronComFolder.py
index 988c5c959..9e06bdf32 100755
--- a/module/plugins/crypter/OronComFolder.py
+++ b/module/plugins/crypter/OronComFolder.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class OronComFolder(DeadCrypter):
- __name__ = "OronComFolder"
+ __name__ = "OronComFolder"
+ __type__ = "crypter"
__version__ = "0.11"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?oron.com/folder/\w+'
+ __pattern__ = r'http://(?:www\.)?oron\.com/folder/\w+'
+ __config__ = []
__description__ = """Oron.com folder decrypter plugin"""
- __author_name__ = "DHMH"
- __author_mail__ = "webmaster@pcProfil.de"
+ __license__ = "GPLv3"
+ __authors__ = [("DHMH", "webmaster@pcProfil.de")]
+
+
+getInfo = create_getInfo(OronComFolder)
diff --git a/module/plugins/crypter/PastebinCom.py b/module/plugins/crypter/PastebinCom.py
index 172a4183f..b3d5a4bea 100644
--- a/module/plugins/crypter/PastebinCom.py
+++ b/module/plugins/crypter/PastebinCom.py
@@ -1,32 +1,24 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class PastebinCom(SimpleCrypter):
- __name__ = "PastebinCom"
- __version__ = "0.01"
- __type__ = "crypter"
+ __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"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
LINK_PATTERN = r'<div class="de\d+">(https?://[^ <]+)(?:[^<]*)</div>'
- TITLE_PATTERN = r'<div class="paste_box_line1" title="(?P<title>[^"]+)">'
+ NAME_PATTERN = r'<div class="paste_box_line1" title="(?P<N>[^"]+)">'
+
+
+getInfo = create_getInfo(PastebinCom)
diff --git a/module/plugins/crypter/QuickshareCzFolder.py b/module/plugins/crypter/QuickshareCzFolder.py
index 1e569a20a..70666b55a 100644
--- a/module/plugins/crypter/QuickshareCzFolder.py
+++ b/module/plugins/crypter/QuickshareCzFolder.py
@@ -5,27 +5,27 @@ from module.plugins.Crypter import Crypter
class QuickshareCzFolder(Crypter):
- __name__ = "QuickshareCzFolder"
- __version__ = "0.1"
- __type__ = "crypter"
+ __name__ = "QuickshareCzFolder"
+ __type__ = "crypter"
+ __version__ = "0.10"
- __pattern__ = r'http://(?:www\.)?quickshare.cz/slozka-\d+.*'
+ __pattern__ = r'http://(?:www\.)?quickshare\.cz/slozka-\d+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Quickshare.cz folder decrypter plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
FOLDER_PATTERN = r'<textarea[^>]*>(.*?)</textarea>'
- LINK_PATTERN = r'(http://www.quickshare.cz/\S+)'
+ LINK_PATTERN = r'(http://www\.quickshare\.cz/\S+)'
def decrypt(self, pyfile):
html = self.load(pyfile.url)
- m = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
+ m = re.search(self.FOLDER_PATTERN, html, re.S)
if m is None:
- self.fail("Parse error (FOLDER)")
+ self.error(_("FOLDER_PATTERN not found"))
self.urls.extend(re.findall(self.LINK_PATTERN, m.group(1)))
-
- if not self.urls:
- self.fail('Could not extract any links')
diff --git a/module/plugins/crypter/RSLayerCom.py b/module/plugins/crypter/RSLayerCom.py
index 637caf2ce..cc3b23bbc 100644
--- a/module/plugins/crypter/RSLayerCom.py
+++ b/module/plugins/crypter/RSLayerCom.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class RSLayerCom(DeadCrypter):
- __name__ = "RSLayerCom"
+ __name__ = "RSLayerCom"
+ __type__ = "crypter"
__version__ = "0.21"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?rs-layer.com/directory-'
+ __pattern__ = r'http://(?:www\.)?rs-layer\.com/directory-'
+ __config__ = []
__description__ = """RS-Layer.com decrypter plugin"""
- __author_name__ = "hzpz"
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = [("hzpz", None)]
+
+
+getInfo = create_getInfo(RSLayerCom)
diff --git a/module/plugins/crypter/RapidfileshareNetFolder.py b/module/plugins/crypter/RapidfileshareNetFolder.py
new file mode 100644
index 000000000..fc3d4241e
--- /dev/null
+++ b/module/plugins/crypter/RapidfileshareNetFolder.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSCrypter import XFSCrypter, create_getInfo
+
+
+class RapidfileshareNetFolder(XFSCrypter):
+ __name__ = "RapidfileshareNetFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
+ __pattern__ = r'http://(?:www\.)?rapidfileshare\.net/users/\w+/\d+/\w+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
+ __description__ = """Rapidfileshare.net folder decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("guidobelix", "guidobelix@hotmail.it")]
+
+
+ HOSTER_DOMAIN = "rapidfileshare.net"
+
+
+getInfo = create_getInfo(RapidfileshareNetFolder)
diff --git a/module/plugins/crypter/RelinkUs.py b/module/plugins/crypter/RelinkUs.py
index 160900144..5933839ec 100644
--- a/module/plugins/crypter/RelinkUs.py
+++ b/module/plugins/crypter/RelinkUs.py
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
import base64
import binascii
import re
@@ -10,48 +12,56 @@ from module.plugins.Crypter import Crypter
class RelinkUs(Crypter):
- __name__ = "RelinkUs"
- __version__ = "3.0"
- __type__ = "crypter"
+ __name__ = "RelinkUs"
+ __type__ = "crypter"
+ __version__ = "3.11"
- __pattern__ = r'http://(?:www\.)?relink.us/(f/|((view|go).php\?id=))(?P<id>.+)'
+ __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"""
- __author_name__ = "fragonib"
- __author_mail__ = "fragonib[AT]yahoo[DOT]es"
+ __license__ = "GPLv3"
+ __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"),
+ ("AndroKev", "neureither.kevin@gmail.com")]
+
- # Constants
PREFERRED_LINK_SOURCES = ["cnl2", "dlc", "web"]
OFFLINE_TOKEN = r'<title>Tattooside'
- PASSWORD_TOKEN = r'container_password\.php'
+
+ 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'
+ 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><i>(.*)</i></td></tr>'
+ 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\('(?P<link>.+)'\)"
- WEB_FORWARD_URL = r'http://www\.relink\.us/frame\.php'
- WEB_LINK_REGEX = r'<iframe name="Container" height="100%" frameborder="no" width="100%" src="(?P<link>.+)"></iframe>'
+ 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.password = None
- self.html = None
self.captcha = False
+
def decrypt(self, pyfile):
# Init
self.initPackage(pyfile)
@@ -63,7 +73,7 @@ class RelinkUs(Crypter):
if not self.isOnline():
self.offline()
- # Check for protection
+ # Check for protection
if self.isPasswordProtected():
self.unlockPasswordProtection()
self.handleErrors()
@@ -87,40 +97,45 @@ class RelinkUs(Crypter):
# Pack
if package_links:
self.packages = [(package_name, package_links, folder_name)]
- else:
- self.fail('Could not extract any links')
+
def initPackage(self, pyfile):
- self.fileid = re.match(self.__pattern__, pyfile.url).group('id')
+ self.fileid = re.match(self.__pattern__, pyfile.url).group('ID')
self.package = pyfile.package()
self.password = self.getPassword()
+
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):
self.logDebug("Submitting password [%s] for protected links" % self.password)
passwd_url = self.PASSWORD_SUBMIT_URL + "?id=%s" % self.fileid
passwd_data = {'id': self.fileid, 'password': self.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
@@ -130,10 +145,11 @@ class RelinkUs(Crypter):
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
+ # 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()
@@ -147,23 +163,24 @@ class RelinkUs(Crypter):
folder = self.package.folder
self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder))
- # Return package info
+ # 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)
+ self.fail(_(msg))
if self.captcha:
if self.CAPTCHA_ERROR_ROKEN in self.html:
- self.logDebug("Invalid captcha, retrying")
self.invalidCaptcha()
self.retry()
else:
self.correctCaptcha()
+
def handleLinkSource(self, source):
if source == 'cnl2':
return self.handleCNL2Links()
@@ -172,12 +189,13 @@ class RelinkUs(Crypter):
elif source == 'web':
return self.handleWEBLinks()
else:
- self.fail('Unknown source [%s] (this is probably a bug)' % source)
+ self.error('Unknown source type "%s" (this is probably a bug)' % source)
+
def handleCNL2Links(self):
self.logDebug("Search for CNL2 links")
package_links = []
- m = re.search(self.CNL2_FORM_REGEX, self.html, re.DOTALL)
+ m = re.search(self.CNL2_FORM_REGEX, self.html, re.S)
if m is not None:
cnl2_form = m.group(1)
try:
@@ -188,8 +206,9 @@ class RelinkUs(Crypter):
self.logDebug("Unable to decrypt CNL2 links")
return package_links
+
def handleDLCLinks(self):
- self.logDebug('Search for DLC links')
+ self.logDebug("Search for DLC links")
package_links = []
m = re.search(self.DLC_LINK_REGEX, self.html)
if m is not None:
@@ -199,45 +218,56 @@ class RelinkUs(Crypter):
dlc = self.load(container_url)
dlc_filename = self.fileid + ".dlc"
dlc_filepath = os.path.join(self.config['general']['download_folder'], dlc_filename)
- f = open(dlc_filepath, "wb")
- f.write(dlc)
- f.close()
+ with open(dlc_filepath, "wb") as f:
+ f.write(dlc)
package_links.append(dlc_filepath)
except:
- self.logDebug("Unable to download DLC container")
+ self.fail("Unable to download DLC container")
return package_links
+
def handleWEBLinks(self):
self.logDebug("Search for WEB links")
+
package_links = []
- fw_params = re.findall(self.WEB_FORWARD_REGEX, self.html)
- self.logDebug("Decrypting %d Web links" % len(fw_params))
- for index, fw_param in enumerate(fw_params):
+ params = re.findall(self.WEB_FORWARD_REGEX, self.html)
+
+ self.logDebug("Decrypting %d Web links" % len(params))
+
+ for index, param in enumerate(params):
try:
- fw_url = self.WEB_FORWARD_URL + "?%s" % fw_param
- self.logDebug("Decrypting Web link %d, %s" % (index + 1, fw_url))
- fw_response = self.load(fw_url, decode=True)
- dl_link = re.search(self.WEB_LINK_REGEX, fw_response).group('link')
- package_links.append(dl_link)
+ 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.IGNORECASE)
+ 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.IGNORECASE)
+ 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)
diff --git a/module/plugins/crypter/SafelinkingNet.py b/module/plugins/crypter/SafelinkingNet.py
index 2687ed2f2..709083b51 100644
--- a/module/plugins/crypter/SafelinkingNet.py
+++ b/module/plugins/crypter/SafelinkingNet.py
@@ -1,66 +1,67 @@
# -*- coding: utf-8 -*-
import re
+
from pycurl import FOLLOWLOCATION
+from BeautifulSoup import BeautifulSoup
+
from module.common.json_layer import json_loads
from module.plugins.Crypter import Crypter
from module.plugins.internal.CaptchaService import SolveMedia
-from module.lib.BeautifulSoup import BeautifulSoup
class SafelinkingNet(Crypter):
- __name__ = "SafelinkingNet"
- __version__ = "0.1"
- __type__ = "crypter"
+ __name__ = "SafelinkingNet"
+ __type__ = "crypter"
+ __version__ = "0.11"
- __pattern__ = r'https?://(?:www\.)?safelinking.net/([pd])/\w+'
+ __pattern__ = r'https?://(?:www\.)?safelinking\.net/([pd])/\w+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Safelinking.net decrypter plugin"""
- __author_name__ = "quareevo"
- __author_mail__ = "quareevo@arcor.de"
+ __license__ = "GPLv3"
+ __authors__ = [("quareevo", "quareevo@arcor.de")]
- SOLVEMEDIA_PATTERN = "solvemediaApiKey = '([\w\.\-_]+)';"
+
+ SOLVEMEDIA_PATTERN = "solvemediaApiKey = '([\w.-]+)';"
def decrypt(self, pyfile):
url = pyfile.url
+
if re.match(self.__pattern__, url).group(1) == "d":
- self.req.http.c.setopt(FOLLOWLOCATION, 0)
- self.load(url)
- m = re.search("^Location: (.+)$", self.req.http.header, re.MULTILINE)
- if m:
- self.urls = [m.group(1)]
+
+ header = self.load(url, just_header=True)
+ if 'location' in header:
+ self.urls = [header['location']]
else:
- self.fail("Couldn't find forwarded Link")
+ self.error(_("Couldn't find forwarded Link"))
else:
- password = ""
postData = {"post-protect": "1"}
- self.html = self.load(url)
-
if "link-password" in self.html:
- password = pyfile.package().password
- postData['link-password'] = password
+ postData['link-password'] = self.getPassword()
if "altcaptcha" in self.html:
- for _ in xrange(5):
+ for _i in xrange(5):
m = re.search(self.SOLVEMEDIA_PATTERN, self.html)
if m:
captchaKey = m.group(1)
captcha = SolveMedia(self)
captchaProvider = "Solvemedia"
else:
- self.fail("Error parsing captcha")
+ self.fail(_("Error parsing captcha"))
challenge, response = captcha.challenge(captchaKey)
postData['adcopy_challenge'] = challenge
- postData['adcopy_response'] = response
+ postData['adcopy_response'] = response
self.html = self.load(url, post=postData)
if "The password you entered was incorrect" in self.html:
- self.fail("Incorrect Password")
+ self.fail(_("Incorrect Password"))
if not "The CAPTCHA code you entered was wrong" in self.html:
break
diff --git a/module/plugins/crypter/SecuredIn.py b/module/plugins/crypter/SecuredIn.py
index 1a6650195..cbfa919ac 100644
--- a/module/plugins/crypter/SecuredIn.py
+++ b/module/plugins/crypter/SecuredIn.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class SecuredIn(DeadCrypter):
- __name__ = "SecuredIn"
+ __name__ = "SecuredIn"
+ __type__ = "crypter"
__version__ = "0.21"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?secured\.in/download-[\d]+-[\w]{8}\.html'
+ __pattern__ = r'http://(?:www\.)?secured\.in/download-[\d]+-\w{8}\.html'
+ __config__ = []
__description__ = """Secured.in decrypter plugin"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __license__ = "GPLv3"
+ __authors__ = [("mkaay", "mkaay@mkaay.de")]
+
+
+getInfo = create_getInfo(SecuredIn)
diff --git a/module/plugins/crypter/SerienjunkiesOrg.py b/module/plugins/crypter/SerienjunkiesOrg.py
deleted file mode 100644
index ea76d30d0..000000000
--- a/module/plugins/crypter/SerienjunkiesOrg.py
+++ /dev/null
@@ -1,323 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import random
-import re
-
-from time import sleep
-
-from module.lib.BeautifulSoup import BeautifulSoup
-from module.plugins.Crypter import Crypter
-from module.unescape import unescape
-
-
-class SerienjunkiesOrg(Crypter):
- __name__ = "SerienjunkiesOrg"
- __version__ = "0.39"
- __type__ = "crypter"
-
- __pattern__ = r'http://(?:www\.)?(serienjunkies.org|dokujunkies.org)/.*?'
- __config__ = [("changeNameSJ", "Packagename;Show;Season;Format;Episode", "Take SJ.org name", "Show"),
- ("changeNameDJ", "Packagename;Show;Format;Episode", "Take DJ.org name", "Show"),
- ("randomPreferred", "bool", "Randomize Preferred-List", False),
- ("hosterListMode", "OnlyOne;OnlyPreferred(One);OnlyPreferred(All);All",
- "Use for hosters (if supported)", "All"),
- ("hosterList", "str", "Preferred Hoster list (comma separated)",
- "RapidshareCom,UploadedTo,NetloadIn,FilefactoryCom,FreakshareNet,FilebaseTo,HotfileCom,DepositfilesCom,EasyshareCom,KickloadCom"),
- ("ignoreList", "str", "Ignored Hoster list (comma separated)", "MegauploadCom")]
-
- __description__ = """Serienjunkies.org decrypter plugin"""
- __author_name__ = ("mkaay", "godofdream")
- __author_mail__ = ("mkaay@mkaay.de", "soilfiction@gmail.com")
-
-
- def setup(self):
- self.multiDL = False
-
- def getSJSrc(self, url):
- src = self.req.load(str(url))
- if "This website is not available in your country" in src:
- self.fail("Not available in your country")
- if not src.find("Enter Serienjunkies") == -1:
- sleep(1)
- src = self.req.load(str(url))
- return src
-
- def handleShow(self, url):
- src = self.getSJSrc(url)
- soup = BeautifulSoup(src)
- packageName = self.pyfile.package().name
- if self.getConfig("changeNameSJ") == "Show":
- found = unescape(soup.find("h2").find("a").string.split(' &#8211;')[0])
- if found:
- packageName = found
-
- nav = soup.find("div", attrs={"id": "scb"})
-
- package_links = []
- for a in nav.findAll("a"):
- if self.getConfig("changeNameSJ") == "Show":
- package_links.append(a['href'])
- else:
- package_links.append(a['href'] + "#hasName")
- if self.getConfig("changeNameSJ") == "Show":
- self.packages.append((packageName, package_links, packageName))
- else:
- self.core.files.addLinks(package_links, self.pyfile.package().id)
-
- def handleSeason(self, url):
- src = self.getSJSrc(url)
- soup = BeautifulSoup(src)
- post = soup.find("div", attrs={"class": "post-content"})
- ps = post.findAll("p")
-
- seasonName = unescape(soup.find("a", attrs={"rel": "bookmark"}).string).replace("&#8211;", "-")
- groups = {}
- gid = -1
- for p in ps:
- if re.search("<strong>Sprache|<strong>Format", str(p)):
- var = p.findAll("strong")
- opts = {"Sprache": "", "Format": ""}
- for v in var:
- n = unescape(v.string).strip()
- n = re.sub(r"^([:]?)(.*?)([:]?)$", r'\2', n)
- if n.strip() not in opts:
- continue
- val = v.nextSibling
- if not val:
- continue
- val = val.replace("|", "").strip()
- val = re.sub(r"^([:]?)(.*?)([:]?)$", r'\2', val)
- opts[n.strip()] = val.strip()
- gid += 1
- groups[gid] = {}
- groups[gid]['ep'] = {}
- groups[gid]['opts'] = opts
- elif re.search("<strong>Download:", str(p)):
- parts = str(p).split("<br />")
- if re.search("<strong>", parts[0]):
- ename = re.search('<strong>(.*?)</strong>', parts[0]).group(1).strip().decode("utf-8").replace(
- "&#8211;", "-")
- groups[gid]['ep'][ename] = {}
- parts.remove(parts[0])
- for part in parts:
- hostername = re.search(r" \| ([-a-zA-Z0-9]+\.\w+)", part)
- if hostername:
- hostername = hostername.group(1)
- groups[gid]['ep'][ename][hostername] = []
- links = re.findall('href="(.*?)"', part)
- for link in links:
- groups[gid]['ep'][ename][hostername].append(link + "#hasName")
-
- links = []
- for g in groups.values():
- for ename in g['ep']:
- links.extend(self.getpreferred(g['ep'][ename]))
- if self.getConfig("changeNameSJ") == "Episode":
- self.packages.append((ename, links, ename))
- links = []
- package = "%s (%s, %s)" % (seasonName, g['opts']['Format'], g['opts']['Sprache'])
- if self.getConfig("changeNameSJ") == "Format":
- self.packages.append((package, links, package))
- links = []
- if (self.getConfig("changeNameSJ") == "Packagename") or re.search("#hasName", url):
- self.core.files.addLinks(links, self.pyfile.package().id)
- elif (self.getConfig("changeNameSJ") == "Season") or not re.search("#hasName", url):
- self.packages.append((seasonName, links, seasonName))
-
- def handleEpisode(self, url):
- src = self.getSJSrc(url)
- if not src.find(
- "Du hast das Download-Limit &uuml;berschritten! Bitte versuche es sp&auml;ter nocheinmal.") == -1:
- self.fail(_("Downloadlimit reached"))
- else:
- soup = BeautifulSoup(src)
- form = soup.find("form")
- h1 = soup.find("h1")
-
- if h1.get("class") == "wrap":
- captchaTag = soup.find(attrs={"src": re.compile("^/secure/")})
- if not captchaTag:
- sleep(5)
- self.retry()
-
- captchaUrl = "http://download.serienjunkies.org" + captchaTag['src']
- result = self.decryptCaptcha(str(captchaUrl), imgtype="png")
- sinp = form.find(attrs={"name": "s"})
-
- self.req.lastURL = str(url)
- sj = self.load(str(url), post={'s': sinp['value'], 'c': result, 'action': "Download"})
-
- soup = BeautifulSoup(sj)
- rawLinks = soup.findAll(attrs={"action": re.compile("^http://download.serienjunkies.org/")})
-
- if not len(rawLinks) > 0:
- sleep(1)
- self.retry()
- return
-
- self.correctCaptcha()
-
- links = []
- for link in rawLinks:
- frameUrl = link['action'].replace("/go-", "/frame/go-")
- links.append(self.handleFrame(frameUrl))
- if re.search("#hasName", url) or ((self.getConfig("changeNameSJ") == "Packagename") and
- (self.getConfig("changeNameDJ") == "Packagename")):
- self.core.files.addLinks(links, self.pyfile.package().id)
- else:
- if h1.text[2] == "_":
- eName = h1.text[3:]
- else:
- eName = h1.text
- self.packages.append((eName, links, eName))
-
- def handleOldStyleLink(self, url):
- sj = self.req.load(str(url))
- soup = BeautifulSoup(sj)
- form = soup.find("form", attrs={"action": re.compile("^http://serienjunkies.org")})
- captchaTag = form.find(attrs={"src": re.compile("^/safe/secure/")})
- captchaUrl = "http://serienjunkies.org" + captchaTag['src']
- result = self.decryptCaptcha(str(captchaUrl))
- url = form['action']
- sinp = form.find(attrs={"name": "s"})
-
- self.req.load(str(url), post={'s': sinp['value'], 'c': result, 'dl.start': "Download"}, cookies=False,
- just_header=True)
- decrypted = self.req.lastEffectiveURL
- if decrypted == str(url):
- self.retry()
- self.core.files.addLinks([decrypted], self.pyfile.package().id)
-
- def handleFrame(self, url):
- self.req.load(str(url))
- return self.req.lastEffectiveURL
-
- def handleShowDJ(self, url):
- src = self.getSJSrc(url)
- soup = BeautifulSoup(src)
- post = soup.find("div", attrs={"id": "page_post"})
- ps = post.findAll("p")
- found = unescape(soup.find("h2").find("a").string.split(' &#8211;')[0])
- if found:
- seasonName = found
-
- groups = {}
- gid = -1
- for p in ps:
- if re.search("<strong>Sprache|<strong>Format", str(p)):
- var = p.findAll("strong")
- opts = {"Sprache": "", "Format": ""}
- for v in var:
- n = unescape(v.string).strip()
- n = re.sub(r"^([:]?)(.*?)([:]?)$", r'\2', n)
- if n.strip() not in opts:
- continue
- val = v.nextSibling
- if not val:
- continue
- val = val.replace("|", "").strip()
- val = re.sub(r"^([:]?)(.*?)([:]?)$", r'\2', val)
- opts[n.strip()] = val.strip()
- gid += 1
- groups[gid] = {}
- groups[gid]['ep'] = {}
- groups[gid]['opts'] = opts
- elif re.search("<strong>Download:", str(p)):
- parts = str(p).split("<br />")
- if re.search("<strong>", parts[0]):
- ename = re.search('<strong>(.*?)</strong>', parts[0]).group(1).strip().decode("utf-8").replace(
- "&#8211;", "-")
- groups[gid]['ep'][ename] = {}
- parts.remove(parts[0])
- for part in parts:
- hostername = re.search(r" \| ([-a-zA-Z0-9]+\.\w+)", part)
- if hostername:
- hostername = hostername.group(1)
- groups[gid]['ep'][ename][hostername] = []
- links = re.findall('href="(.*?)"', part)
- for link in links:
- groups[gid]['ep'][ename][hostername].append(link + "#hasName")
-
- links = []
- for g in groups.values():
- for ename in g['ep']:
- links.extend(self.getpreferred(g['ep'][ename]))
- if self.getConfig("changeNameDJ") == "Episode":
- self.packages.append((ename, links, ename))
- links = []
- package = "%s (%s, %s)" % (seasonName, g['opts']['Format'], g['opts']['Sprache'])
- if self.getConfig("changeNameDJ") == "Format":
- self.packages.append((package, links, package))
- links = []
- if (self.getConfig("changeNameDJ") == "Packagename") or re.search("#hasName", url):
- self.core.files.addLinks(links, self.pyfile.package().id)
- elif (self.getConfig("changeNameDJ") == "Show") or not re.search("#hasName", url):
- self.packages.append((seasonName, links, seasonName))
-
- def handleCategoryDJ(self, url):
- package_links = []
- src = self.getSJSrc(url)
- soup = BeautifulSoup(src)
- content = soup.find("div", attrs={"id": "content"})
- for a in content.findAll("a", attrs={"rel": "bookmark"}):
- package_links.append(a['href'])
- self.core.files.addLinks(package_links, self.pyfile.package().id)
-
- def decrypt(self, pyfile):
- showPattern = re.compile("^http://serienjunkies.org/serie/(.*)/$")
- seasonPattern = re.compile("^http://serienjunkies.org/.*?/(.*)/$")
- episodePattern = re.compile("^http://download.serienjunkies.org/f-.*?.html(#hasName)?$")
- oldStyleLink = re.compile("^http://serienjunkies.org/safe/(.*)$")
- categoryPatternDJ = re.compile("^http://dokujunkies.org/.*?(.*)$")
- showPatternDJ = re.compile(r"^http://dokujunkies.org/.*?/(.*)\.html(#hasName)?$")
- framePattern = re.compile("^http://download.(serienjunkies.org|dokujunkies.org)/frame/go-.*?/$")
- url = pyfile.url
- if framePattern.match(url):
- self.packages.append((pyfile.package().name, [self.handleFrame(url)], pyfile.package().name))
- elif episodePattern.match(url):
- self.handleEpisode(url)
- elif oldStyleLink.match(url):
- self.handleOldStyleLink(url)
- elif showPattern.match(url):
- self.handleShow(url)
- elif showPatternDJ.match(url):
- self.handleShowDJ(url)
- elif seasonPattern.match(url):
- self.handleSeason(url)
- elif categoryPatternDJ.match(url):
- self.handleCategoryDJ(url)
-
- #selects the preferred hoster, after that selects any hoster (ignoring the one to ignore)
- def getpreferred(self, hosterlist):
-
- result = []
- preferredList = self.getConfig("hosterList").strip().lower().replace(
- '|', ',').replace('.', '').replace(';', ',').split(',')
- if (self.getConfig("randomPreferred") is True) and (
- self.getConfig("hosterListMode") in ["OnlyOne", "OnlyPreferred(One)"]):
- random.shuffle(preferredList)
- # we don't want hosters be read two times
- hosterlist2 = hosterlist.copy()
-
- for preferred in preferredList:
- for Hoster in hosterlist:
- if preferred == Hoster.lower().replace('.', ''):
- for Part in hosterlist[Hoster]:
- self.logDebug("selected " + Part)
- result.append(str(Part))
- del (hosterlist2[Hoster])
- if self.getConfig("hosterListMode") in ["OnlyOne", "OnlyPreferred(One)"]:
- return result
-
- ignorelist = self.getConfig("ignoreList").strip().lower().replace(
- '|', ',').replace('.', '').replace(';', ',').split(',')
- if self.getConfig('hosterListMode') in ["OnlyOne", "All"]:
- for Hoster in hosterlist2:
- if Hoster.strip().lower().replace('.', '') not in ignorelist:
- for Part in hosterlist2[Hoster]:
- self.logDebug("selected2 " + Part)
- result.append(str(Part))
-
- if self.getConfig('hosterListMode') == "OnlyOne":
- return result
- return result
diff --git a/module/plugins/crypter/SexuriaCom.py b/module/plugins/crypter/SexuriaCom.py
new file mode 100644
index 000000000..3c952fd6b
--- /dev/null
+++ b/module/plugins/crypter/SexuriaCom.py
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.Crypter import Crypter
+
+
+class SexuriaCom(Crypter):
+ __name__ = "SexuriaCom"
+ __type__ = "crypter"
+ __version__ = "0.01"
+
+ __pattern__ = r'http://(?:www\.)?sexuria\.com/(v1/)?(Pornos_Kostenlos_.+?_(\d+)\.html|dl_links_\d+_\d+\.html|id=\d+\&part=\d+\&link=\d+)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
+ __description__ = """Sexuria.com decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("NETHead", "NETHead.AT.gmx.DOT.net")]
+
+
+ PATTERN_SUPPORTED_MAIN = re.compile(r'http://(www\.)?sexuria\.com/(v1/)?Pornos_Kostenlos_.+?_(\d+)\.html', flags=re.I)
+ PATTERN_SUPPORTED_CRYPT = re.compile(r'http://(www\.)?sexuria\.com/(v1/)?dl_links_\d+_(?P<ID>\d+)\.html', flags=re.I)
+ PATTERN_SUPPORTED_REDIRECT = re.compile(r'http://(www\.)?sexuria\.com/out\.php\?id=(?P<ID>\d+)\&part=\d+\&link=\d+', flags=re.I)
+ PATTERN_TITLE = re.compile(r'<title> - (?P<TITLE>.*) Sexuria - Kostenlose Pornos - Rapidshare XXX Porn</title>', flags=re.I)
+ PATTERN_PASSWORD = re.compile(r'<strong>Passwort: </strong></div></td>.*?bgcolor="#EFEFEF">(?P<PWD>.*?)</td>', flags=re.I | re.S)
+ PATTERN_DL_LINK_PAGE = re.compile(r'"(dl_links_\d+_\d+\.html)"', flags=re.I)
+ PATTERN_REDIRECT_LINKS = re.compile(r'value="(http://sexuria\.com/out\.php\?id=\d+\&part=\d+\&link=\d+)" readonly', flags=re.I)
+
+
+ def decrypt(self, pyfile):
+ # Init
+ self.pyfile = pyfile
+ self.package = pyfile.package()
+
+ # Get package links
+ package_name, self.links, folder_name, package_pwd = self.decryptLinks(self.pyfile.url)
+ self.packages = [(package_name, self.links, folder_name)]
+
+
+ def decryptLinks(self, url):
+ linklist = []
+ name = self.package.name
+ folder = self.package.folder
+ password = None
+
+ if re.match(self.PATTERN_SUPPORTED_MAIN, url):
+ # Processing main page
+ html = self.load(url)
+ links = re.findall(self.PATTERN_DL_LINK_PAGE, html)
+ for link in links:
+ linklist.append("http://sexuria.com/v1/" + link)
+
+ elif re.match(self.PATTERN_SUPPORTED_REDIRECT, url):
+ # Processing direct redirect link (out.php), redirecting to main page
+ id = re.search(self.PATTERN_SUPPORTED_REDIRECT, url).group('ID')
+ if id:
+ linklist.append("http://sexuria.com/v1/Pornos_Kostenlos_liebe_%s.html" % id)
+
+ elif re.match(self.PATTERN_SUPPORTED_CRYPT, url):
+ # Extract info from main file
+ id = re.search(self.PATTERN_SUPPORTED_CRYPT, url).group('ID')
+ html = self.load("http://sexuria.com/v1/Pornos_Kostenlos_info_%s.html" % id, decode=True)
+
+ title = re.search(self.PATTERN_TITLE, html).group('TITLE').strip()
+ if title:
+ name = folder = title
+ self.logDebug("Package info found, name [%s] and folder [%s]" % (name, folder))
+
+ pwd = re.search(self.PATTERN_PASSWORD, html).group('PWD')
+ if pwd:
+ password = pwd.strip()
+ self.logDebug("Password info [%s] found" % password)
+
+ # Process link (dl_link)
+ html = self.load(url)
+ links = re.findall(self.PATTERN_REDIRECT_LINKS, html)
+ if len(links) == 0:
+ self.LogError("Broken for link %s" % link)
+ else:
+ for link in links:
+ link = link.replace("http://sexuria.com/", "http://www.sexuria.com/")
+ finallink = self.load(link, just_header=True)['location']
+ if not finallink or "sexuria.com/" in finallink:
+ self.LogError("Broken for link %s" % link)
+ else:
+ linklist.append(finallink)
+
+ # Debug log
+ self.logDebug("%d supported links" % len(linklist))
+ for i, link in enumerate(linklist):
+ self.logDebug("Supported link %d, %s" % (i + 1, link))
+
+ return name, linklist, folder, password
diff --git a/module/plugins/crypter/ShareLinksBiz.py b/module/plugins/crypter/ShareLinksBiz.py
index b56f90e15..d2e8138f6 100644
--- a/module/plugins/crypter/ShareLinksBiz.py
+++ b/module/plugins/crypter/ShareLinksBiz.py
@@ -9,24 +9,26 @@ from module.plugins.Crypter import Crypter
class ShareLinksBiz(Crypter):
- __name__ = "ShareLinksBiz"
- __version__ = "1.13"
- __type__ = "crypter"
+ __name__ = "ShareLinksBiz"
+ __type__ = "crypter"
+ __version__ = "1.14"
__pattern__ = r'http://(?:www\.)?(share-links|s2l)\.biz/(?P<ID>_?\w+)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Share-Links.biz decrypter plugin"""
- __author_name__ = "fragonib"
- __author_mail__ = "fragonib[AT]yahoo[DOT]es"
+ __license__ = "GPLv3"
+ __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es")]
def setup(self):
self.baseUrl = None
self.fileId = None
self.package = None
- self.html = None
self.captcha = False
+
def decrypt(self, pyfile):
# Init
self.initFile(pyfile)
@@ -61,6 +63,7 @@ class ShareLinksBiz(Crypter):
# Pack
self.packages = [(package_name, package_links, package_folder)]
+
def initFile(self, pyfile):
url = pyfile.url
if 's2l.biz' in url:
@@ -69,29 +72,34 @@ class ShareLinksBiz(Crypter):
self.fileId = re.match(self.__pattern__, url).group('ID')
self.package = pyfile.package()
+
def isOnline(self):
if "No usable content was found" in self.html:
self.logDebug("File not found")
return False
return True
+
def isPasswordProtected(self):
if re.search(r'''<form.*?id="passwordForm".*?>''', self.html):
self.logDebug("Links are protected")
return True
return False
+
def isCaptchaProtected(self):
if '<map id="captchamap"' in self.html:
self.logDebug("Links are captcha protected")
return True
return False
+
def unblockServer(self):
imgs = re.findall(r"(/template/images/.*?\.gif)", self.html)
for img in imgs:
self.load(self.baseUrl + img)
+
def unlockPasswordProtection(self):
password = self.getPassword()
self.logDebug("Submitting password [%s] for protected links" % password)
@@ -99,6 +107,7 @@ class ShareLinksBiz(Crypter):
url = self.baseUrl + '/' + self.fileId
self.html = self.load(url, post=post, decode=True)
+
def unlockCaptchaProtection(self):
# Get captcha map
captchaMap = self._getCaptchaMap()
@@ -114,14 +123,12 @@ class ShareLinksBiz(Crypter):
# Resolve captcha
href = self._resolveCoords(coords, captchaMap)
if href is None:
- self.logDebug("Invalid captcha resolving, retrying")
self.invalidCaptcha()
- self.setWait(5, False)
- self.wait()
- self.retry()
+ self.retry(wait_time=5)
url = self.baseUrl + href
self.html = self.load(url, decode=True)
+
def _getCaptchaMap(self):
mapp = {}
for m in re.finditer(r'<area shape="rect" coords="(.*?)" href="(.*?)"', self.html):
@@ -130,34 +137,34 @@ class ShareLinksBiz(Crypter):
mapp[rect] = href
return mapp
+
def _resolveCoords(self, coords, captchaMap):
x, y = coords
- for rect, href in captchaMap.items():
+ for rect, href in captchaMap.iteritems():
x1, y1, x2, y2 = rect
if (x >= x1 and x <= x2) and (y >= y1 and y <= y2):
return href
+
def handleErrors(self):
if "The inserted password was wrong" in self.html:
self.logDebug("Incorrect password, please set right password on 'Edit package' form and retry")
- self.fail("Incorrect password, please set right password on 'Edit package' form and retry")
+ self.fail(_("Incorrect password, please set right password on 'Edit package' form and retry"))
if self.captcha:
if "Your choice was wrong" in self.html:
- self.logDebug("Invalid captcha, retrying")
self.invalidCaptcha()
- self.setWait(5)
- self.wait()
- self.retry()
+ self.retry(wait_time=5)
else:
self.correctCaptcha()
+
def getPackageInfo(self):
name = folder = None
# Extract from web package header
title_re = r'<h2><img.*?/>(.*)</h2>'
- m = re.search(title_re, self.html, re.DOTALL)
+ m = re.search(title_re, self.html, re.S)
if m is not None:
title = m.group(1).strip()
if 'unnamed' not in title:
@@ -173,38 +180,45 @@ class ShareLinksBiz(Crypter):
# Return package info
return name, folder
+
def handleWebLinks(self):
package_links = []
self.logDebug("Handling Web links")
#@TODO: Gather paginated web links
- pattern = r"javascript:_get\('(.*?)', \d+, ''\)"
+ pattern = r'javascript:_get\(\'(.*?)\', \d+, \'\'\)'
ids = re.findall(pattern, self.html)
self.logDebug("Decrypting %d Web links" % len(ids))
for i, ID in enumerate(ids):
try:
self.logDebug("Decrypting Web link %d, [%s]" % (i + 1, ID))
+
dwLink = self.baseUrl + "/get/lnk/" + ID
- response = self.load(dwLink)
- code = re.search(r'frm/(\d+)', response).group(1)
+ res = self.load(dwLink)
+
+ code = re.search(r'frm/(\d+)', res).group(1)
fwLink = self.baseUrl + "/get/frm/" + code
- response = self.load(fwLink)
- jscode = re.search(r'<script language="javascript">\s*eval\((.*)\)\s*</script>', response,
- re.DOTALL).group(1)
+ res = self.load(fwLink)
+
+ jscode = re.search(r'<script language="javascript">\s*eval\((.*)\)\s*</script>', res, re.S).group(1)
jscode = self.js.eval("f = %s" % jscode)
jslauncher = "window=''; parent={frames:{Main:{location:{href:''}}},location:''}; %s; parent.frames.Main.location.href"
+
dlLink = self.js.eval(jslauncher % jscode)
+
self.logDebug("JsEngine returns value [%s] for redirection link" % dlLink)
+
package_links.append(dlLink)
except Exception, detail:
self.logDebug("Error decrypting Web link [%s], %s" % (ID, detail))
return package_links
+
def handleContainers(self):
package_links = []
self.logDebug("Handling Container links")
- pattern = r"javascript:_get\('(.*?)', 0, '(rsdf|ccf|dlc)'\)"
+ pattern = r'javascript:_get\(\'(.*?)\', 0, \'(rsdf|ccf|dlc)\'\)'
containersLinks = re.findall(pattern, self.html)
self.logDebug("Decrypting %d Container links" % len(containersLinks))
for containerLink in containersLinks:
@@ -212,6 +226,7 @@ class ShareLinksBiz(Crypter):
package_links.append(link)
return package_links
+
def handleCNL2(self):
package_links = []
self.logDebug("Handling CNL2 links")
@@ -221,15 +236,16 @@ class ShareLinksBiz(Crypter):
(crypted, jk) = self._getCipherParams()
package_links.extend(self._getLinks(crypted, jk))
except:
- self.fail("Unable to decrypt CNL2 links")
+ self.fail(_("Unable to decrypt CNL2 links"))
return package_links
+
def _getCipherParams(self):
# Request CNL2
- code = re.search(r'ClicknLoad.swf\?code=(.*?)"', self.html).group(1)
- url = "%s/get/cnl2/%s" % (self.baseUrl, code)
- response = self.load(url)
- params = response.split(";;")
+ code = re.search(r'ClicknLoad.swf\?code=(.*?)"', self.html).group(1)
+ url = "%s/get/cnl2/%s" % (self.baseUrl, code)
+ res = self.load(url)
+ params = res.split(";;")
# Get jk
strlist = list(base64.standard_b64decode(params[1]))
@@ -244,6 +260,7 @@ class ShareLinksBiz(Crypter):
# Log and return
return crypted, jk
+
def _getLinks(self, crypted, jk):
# Get key
jreturn = self.js.eval("%s f()" % jk)
diff --git a/module/plugins/crypter/ShareRapidComFolder.py b/module/plugins/crypter/ShareRapidComFolder.py
deleted file mode 100644
index e44402a52..000000000
--- a/module/plugins/crypter/ShareRapidComFolder.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
-
-
-class ShareRapidComFolder(SimpleCrypter):
- __name__ = "ShareRapidComFolder"
- __version__ = "0.01"
- __type__ = "crypter"
-
- __pattern__ = r'http://(?:www\.)?((share(-?rapid\.(biz|com|cz|info|eu|net|org|pl|sk)|-(central|credit|free|net)\.cz|-ms\.net)|(s-?rapid|rapids)\.(cz|sk))|(e-stahuj|mediatack|premium-rapidshare|rapidshare-premium|qiuck)\.cz|kadzet\.com|stahuj-zdarma\.eu|strelci\.net|universal-share\.com)/(slozka/.+)'
-
- __description__ = """Share-Rapid.com folder decrypter plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
- LINK_PATTERN = r'<td class="soubor"[^>]*><a href="([^"]+)">'
diff --git a/module/plugins/crypter/SharingmatrixComFolder.py b/module/plugins/crypter/SharingmatrixComFolder.py
new file mode 100644
index 000000000..e16bdf814
--- /dev/null
+++ b/module/plugins/crypter/SharingmatrixComFolder.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
+
+
+class SharingmatrixComFolder(DeadCrypter):
+ __name__ = "SharingmatrixComFolder"
+ __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(SharingmatrixComFolder)
diff --git a/module/plugins/crypter/SpeedLoadOrgFolder.py b/module/plugins/crypter/SpeedLoadOrgFolder.py
index 305397d3c..ddde7dec2 100644
--- a/module/plugins/crypter/SpeedLoadOrgFolder.py
+++ b/module/plugins/crypter/SpeedLoadOrgFolder.py
@@ -1,29 +1,19 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class SpeedLoadOrgFolder(DeadCrypter):
- __name__ = "SpeedLoadOrgFolder"
- __version__ = "0.3"
- __type__ = "crypter"
+ __name__ = "SpeedLoadOrgFolder"
+ __type__ = "crypter"
+ __version__ = "0.30"
__pattern__ = r'http://(?:www\.)?speedload\.org/(\d+~f$|folder/\d+/)'
+ __config__ = []
__description__ = """Speedload decrypter plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
+
+getInfo = create_getInfo(SpeedLoadOrgFolder)
diff --git a/module/plugins/crypter/StealthTo.py b/module/plugins/crypter/StealthTo.py
index 9cae7ba20..5173421f1 100644
--- a/module/plugins/crypter/StealthTo.py
+++ b/module/plugins/crypter/StealthTo.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class StealthTo(DeadCrypter):
- __name__ = "StealthTo"
- __version__ = "0.2"
- __type__ = "crypter"
+ __name__ = "StealthTo"
+ __type__ = "crypter"
+ __version__ = "0.20"
__pattern__ = r'http://(?:www\.)?stealth\.to/folder/.+'
+ __config__ = []
__description__ = """Stealth.to decrypter plugin"""
- __author_name__ = "spoob"
- __author_mail__ = "spoob@pyload.org"
+ __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
index 3ff9aa5dd..d36128550 100644
--- a/module/plugins/crypter/TnyCz.py
+++ b/module/plugins/crypter/TnyCz.py
@@ -1,39 +1,30 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
import re
class TnyCz(SimpleCrypter):
- __name__ = "TnyCz"
- __version__ = "0.01"
- __type__ = "crypter"
+ __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"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- TITLE_PATTERN = r'<title>(?P<title>.+) - .+</title>'
+
+ 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
index 2c7bb2c9f..10780dd45 100644
--- a/module/plugins/crypter/TrailerzoneInfo.py
+++ b/module/plugins/crypter/TrailerzoneInfo.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class TrailerzoneInfo(DeadCrypter):
- __name__ = "TrailerzoneInfo"
+ __name__ = "TrailerzoneInfo"
+ __type__ = "crypter"
__version__ = "0.03"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?trailerzone.info/.*?'
+ __pattern__ = r'http://(?:www\.)?trailerzone\.info/.+'
+ __config__ = []
__description__ = """TrailerZone.info decrypter plugin"""
- __author_name__ = "godofdream"
- __author_mail__ = "soilfiction@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("godofdream", "soilfiction@gmail.com")]
+
+
+getInfo = create_getInfo(TrailerzoneInfo)
diff --git a/module/plugins/crypter/TurbobitNetFolder.py b/module/plugins/crypter/TurbobitNetFolder.py
index 26923e8d4..c6734c997 100644
--- a/module/plugins/crypter/TurbobitNetFolder.py
+++ b/module/plugins/crypter/TurbobitNetFolder.py
@@ -1,37 +1,27 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
from module.common.json_layer import json_loads
class TurbobitNetFolder(SimpleCrypter):
- __name__ = "TurbobitNetFolder"
- __version__ = "0.03"
- __type__ = "crypter"
+ __name__ = "TurbobitNetFolder"
+ __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"""
- __author_name__ = ("stickell", "Walter Purcaro")
- __author_mail__ = ("l.stickell@yahoo.it", "vuolter@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
- TITLE_PATTERN = r"src='/js/lib/grid/icon/folder.png'> <span>(?P<title>.+?)</span>"
+
+ NAME_PATTERN = r'src=\'/js/lib/grid/icon/folder.png\'> <span>(?P<N>.+?)</span>'
def _getLinks(self, id, page=1):
@@ -47,7 +37,11 @@ class TurbobitNetFolder(SimpleCrypter):
else:
return
+
def getLinks(self):
- id = re.match(self.__pattern__, self.pyfile.url).group("ID")
+ 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/TusfilesNetFolder.py b/module/plugins/crypter/TusfilesNetFolder.py
index 70b7bd4b9..0db3470cc 100644
--- a/module/plugins/crypter/TusfilesNetFolder.py
+++ b/module/plugins/crypter/TusfilesNetFolder.py
@@ -1,47 +1,38 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
import math
import re
from urlparse import urljoin
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.XFSCrypter import XFSCrypter, create_getInfo
-class TusfilesNetFolder(SimpleCrypter):
- __name__ = "TusfilesNetFolder"
- __version__ = "0.02"
- __type__ = "crypter"
+class TusfilesNetFolder(XFSCrypter):
+ __name__ = "TusfilesNetFolder"
+ __type__ = "crypter"
+ __version__ = "0.07"
- __pattern__ = r'https?://(?:www\.)?tusfiles\.net/go/(?P<ID>\w+)/?'
+ __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"""
- __author_name__ = ("Walter Purcaro", "stickell")
- __author_mail__ = ("vuolter@gmail.com", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
- LINK_PATTERN = r'<TD align=left><a href="(.*?)">'
- TITLE_PATTERN = r'<Title>.*?\: (?P<title>.+) folder</Title>'
- PAGES_PATTERN = r'>\((?P<pages>\d+) \w+\)<'
- URL_REPLACEMENTS = [(__pattern__, r'https://www.tusfiles.net/go/\g<ID>/')]
+ HOSTER_DOMAIN = "tusfiles.net"
+
+ 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 handleMultiPages(self):
pages = re.search(self.PAGES_PATTERN, self.html)
if pages:
@@ -51,4 +42,7 @@ class TusfilesNetFolder(SimpleCrypter):
for p in xrange(2, pages + 1):
self.html = self.loadPage(p)
- self.package_links += self.getLinks()
+ self.links += self.getLinks()
+
+
+getInfo = create_getInfo(TusfilesNetFolder)
diff --git a/module/plugins/crypter/UlozToFolder.py b/module/plugins/crypter/UlozToFolder.py
index dfa1bb8c4..a1f3ed5ea 100644
--- a/module/plugins/crypter/UlozToFolder.py
+++ b/module/plugins/crypter/UlozToFolder.py
@@ -5,15 +5,18 @@ from module.plugins.Crypter import Crypter
class UlozToFolder(Crypter):
- __name__ = "UlozToFolder"
- __version__ = "0.2"
- __type__ = "crypter"
+ __name__ = "UlozToFolder"
+ __type__ = "crypter"
+ __version__ = "0.20"
- __pattern__ = r'http://(?:www\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj.cz|zachowajto.pl)/(m|soubory)/.*'
+ __pattern__ = r'http://(?:www\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj\.cz|zachowajto\.pl)/(m|soubory)/.+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Uloz.to folder decrypter plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
FOLDER_PATTERN = r'<ul class="profile_files">(.*?)</ul>'
LINK_PATTERN = r'<br /><a href="/([^"]+)">[^<]+</a>'
@@ -25,10 +28,10 @@ class UlozToFolder(Crypter):
new_links = []
for i in xrange(1, 100):
- self.logInfo("Fetching links from page %i" % i)
- m = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
+ self.logInfo(_("Fetching links from page %i") % i)
+ m = re.search(self.FOLDER_PATTERN, html, re.S)
if m is None:
- self.fail("Parse error (FOLDER)")
+ self.error(_("FOLDER_PATTERN not found"))
new_links.extend(re.findall(self.LINK_PATTERN, m.group(1)))
m = re.search(self.NEXT_PAGE_PATTERN, html)
@@ -37,9 +40,7 @@ class UlozToFolder(Crypter):
else:
break
else:
- self.logInfo("Limit of 99 pages reached, aborting")
+ self.logInfo(_("Limit of 99 pages reached, aborting"))
if new_links:
self.urls = [map(lambda s: "http://ulozto.net/%s" % s, new_links)]
- else:
- self.fail('Could not extract any links')
diff --git a/module/plugins/crypter/UploadableChFolder.py b/module/plugins/crypter/UploadableChFolder.py
new file mode 100644
index 000000000..22f9ca2ed
--- /dev/null
+++ b/module/plugins/crypter/UploadableChFolder.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
+
+
+class UploadableChFolder(SimpleCrypter):
+ __name__ = "UploadableChFolder"
+ __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>&nbsp;</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/UploadedToFolder.py b/module/plugins/crypter/UploadedToFolder.py
index 36dd9714a..0a71add70 100644
--- a/module/plugins/crypter/UploadedToFolder.py
+++ b/module/plugins/crypter/UploadedToFolder.py
@@ -1,52 +1,37 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from urlparse import urljoin
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class UploadedToFolder(SimpleCrypter):
- __name__ = "UploadedToFolder"
- __version__ = "0.3"
- __type__ = "crypter"
+ __name__ = "UploadedToFolder"
+ __type__ = "crypter"
+ __version__ = "0.42"
- __pattern__ = r'http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|folder|list)/(?P<id>\w+)'
+ __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"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- PLAIN_PATTERN = r'<small class="date"><a href="(?P<plain>[\w/]+)" onclick='
- TITLE_PATTERN = r'<title>(?P<title>[^<]+)</title>'
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
- def decrypt(self, pyfile):
- self.html = self.load(pyfile.url)
+ PLAIN_PATTERN = r'<small class="date"><a href="([\w/]+)" onclick='
+ NAME_PATTERN = r'<title>(?P<N>.+?)<'
- package_name, folder_name = self.getPackageNameAndFolder()
+ def getLinks(self):
m = re.search(self.PLAIN_PATTERN, self.html)
- if m:
- plain_link = 'http://uploaded.net/' + m.group('plain')
- else:
- self.fail('Parse error - Unable to find plain url list')
+ 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]
- self.html = self.load(plain_link)
- package_links = self.html.split('\n')[:-1]
- self.logDebug('Package has %d links' % len(package_links))
- self.packages = [(package_name, package_links, folder_name)]
+getInfo = create_getInfo(UploadedToFolder)
diff --git a/module/plugins/crypter/WiiReloadedOrg.py b/module/plugins/crypter/WiiReloadedOrg.py
index 9cb0751d8..c3c5b8222 100644
--- a/module/plugins/crypter/WiiReloadedOrg.py
+++ b/module/plugins/crypter/WiiReloadedOrg.py
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.DeadCrypter import DeadCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
class WiiReloadedOrg(DeadCrypter):
- __name__ = "WiiReloadedOrg"
+ __name__ = "WiiReloadedOrg"
+ __type__ = "crypter"
__version__ = "0.11"
- __type__ = "crypter"
__pattern__ = r'http://(?:www\.)?wii-reloaded\.org/protect/get\.php\?i=.+'
+ __config__ = []
__description__ = """Wii-Reloaded.org decrypter plugin"""
- __author_name__ = "hzpz"
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = [("hzpz", None)]
+
+
+getInfo = create_getInfo(WiiReloadedOrg)
diff --git a/module/plugins/crypter/WuploadComFolder.py b/module/plugins/crypter/WuploadComFolder.py
new file mode 100644
index 000000000..873c71fad
--- /dev/null
+++ b/module/plugins/crypter/WuploadComFolder.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
+
+
+class WuploadComFolder(DeadCrypter):
+ __name__ = "WuploadComFolder"
+ __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(WuploadComFolder)
diff --git a/module/plugins/crypter/XFileSharingProFolder.py b/module/plugins/crypter/XFileSharingProFolder.py
new file mode 100644
index 000000000..10e4d8c83
--- /dev/null
+++ b/module/plugins/crypter/XFileSharingProFolder.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.internal.XFSCrypter import XFSCrypter, create_getInfo
+
+
+class XFileSharingProFolder(XFSCrypter):
+ __name__ = "XFileSharingProFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
+ __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(XFileSharingProFolder, self).init()
+
+ self.__pattern__ = self.core.pluginManager.crypterPlugins[self.__name__]['pattern']
+
+ self.HOSTER_DOMAIN = re.match(self.__pattern__, self.pyfile.url).group(1).lower()
+ self.HOSTER_NAME = "".join([str.capitalize() for str in self.HOSTER_DOMAIN.split('.')])
+
+ 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/crypter/XupPl.py b/module/plugins/crypter/XupPl.py
index e89f4ccb0..f2ecbee5a 100644
--- a/module/plugins/crypter/XupPl.py
+++ b/module/plugins/crypter/XupPl.py
@@ -4,15 +4,17 @@ from module.plugins.Crypter import Crypter
class XupPl(Crypter):
- __name__ = "XupPl"
- __version__ = "0.1"
- __type__ = "crypter"
+ __name__ = "XupPl"
+ __type__ = "crypter"
+ __version__ = "0.10"
- __pattern__ = r'https?://(?:[^/]*\.)?xup\.pl/.*'
+ __pattern__ = r'https?://(?:[^/]*\.)?xup\.pl/.+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
__description__ = """Xup.pl decrypter plugin"""
- __author_name__ = "z00nx"
- __author_mail__ = "z00nx0@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("z00nx", "z00nx0@gmail.com")]
def decrypt(self, pyfile):
@@ -20,4 +22,4 @@ class XupPl(Crypter):
if 'location' in header:
self.urls = [header['location']]
else:
- self.fail('Unable to find link')
+ self.fail(_("Unable to find link"))
diff --git a/module/plugins/crypter/YoutubeBatch.py b/module/plugins/crypter/YoutubeBatch.py
index 216fbb670..73ebf5fb3 100644
--- a/module/plugins/crypter/YoutubeBatch.py
+++ b/module/plugins/crypter/YoutubeBatch.py
@@ -1,20 +1,5 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from urlparse import urljoin
@@ -23,30 +8,34 @@ from module.common.json_layer import json_loads
from module.plugins.Crypter import Crypter
from module.utils import save_join
-API_URL = "AIzaSyCKnWLNlkX-L4oD1aEzqqhRw1zczeD6_k0"
-
class YoutubeBatch(Crypter):
- __name__ = "YoutubeBatch"
- __version__ = "1.00"
- __type__ = "crypter"
+ __name__ = "YoutubeBatch"
+ __type__ = "crypter"
+ __version__ = "1.01"
__pattern__ = r'https?://(?:www\.|m\.)?youtube\.com/(?P<TYPE>user|playlist|view_play_list)(/|.*?[?&](?:list|p)=)(?P<ID>[\w-]+)'
- __config__ = [("likes", "bool", "Grab user (channel) liked videos", False),
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True),
+ ("likes", "bool", "Grab user (channel) liked videos", False),
("favorites", "bool", "Grab user (channel) favorite videos", False),
("uploads", "bool", "Grab channel unplaylisted videos", True)]
__description__ = """Youtube.com channel & playlist decrypter plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ API_KEY = "AIzaSyCKnWLNlkX-L4oD1aEzqqhRw1zczeD6_k0"
def api_response(self, ref, req):
- req.update({"key": API_KEY})
+ req.update({"key": self.API_KEY})
url = urljoin("https://www.googleapis.com/youtube/v3/", ref)
page = self.load(url, get=req)
return json_loads(page)
+
def getChannel(self, user):
channels = self.api_response("channels", {"part": "id,snippet,contentDetails", "forUsername": user, "maxResults": "50"})
if channels['items']:
@@ -56,6 +45,7 @@ class YoutubeBatch(Crypter):
"relatedPlaylists": channel['contentDetails']['relatedPlaylists'],
"user": user} # One lone channel for user?
+
def getPlaylist(self, p_id):
playlists = self.api_response("playlists", {"part": "snippet", "id": p_id})
if playlists['items']:
@@ -65,6 +55,7 @@ class YoutubeBatch(Crypter):
"channelId": playlist['snippet']['channelId'],
"channelTitle": playlist['snippet']['channelTitle']}
+
def _getPlaylists(self, id, token=None):
req = {"part": "id", "maxResults": "50", "channelId": id}
if token:
@@ -79,9 +70,11 @@ class YoutubeBatch(Crypter):
for item in self._getPlaylists(id, playlists['nextPageToken']):
yield item
+
def getPlaylists(self, ch_id):
return map(self.getPlaylist, self._getPlaylists(ch_id))
+
def _getVideosId(self, id, token=None):
req = {"part": "contentDetails", "maxResults": "50", "playlistId": id}
if token:
@@ -96,13 +89,15 @@ class YoutubeBatch(Crypter):
for item in self._getVideosId(id, playlist['nextPageToken']):
yield item
+
def getVideosId(self, p_id):
return list(self._getVideosId(p_id))
+
def decrypt(self, pyfile):
m = re.match(self.__pattern__, pyfile.url)
- m_id = m.group("ID")
- m_type = m.group("TYPE")
+ m_id = m.group('ID')
+ m_type = m.group('TYPE')
if m_type == "user":
self.logDebug("Url recognized as Channel")
@@ -130,7 +125,7 @@ class YoutubeBatch(Crypter):
playlists = [self.getPlaylist(m_id)]
if not playlists:
- self.fail("No playlist available")
+ self.fail(_("No playlist available"))
addedvideos = []
urlize = lambda x: "https://www.youtube.com/watch?v=" + x
diff --git a/module/plugins/hooks/AlldebridCom.py b/module/plugins/hooks/AlldebridCom.py
index 1ef9b252a..d5986053f 100644
--- a/module/plugins/hooks/AlldebridCom.py
+++ b/module/plugins/hooks/AlldebridCom.py
@@ -1,30 +1,27 @@
# -*- coding: utf-8 -*-
-# should be working
-
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class AlldebridCom(MultiHoster):
- __name__ = "AlldebridCom"
- __version__ = "0.13"
- __type__ = "hook"
+class AlldebridCom(MultiHook):
+ __name__ = "AlldebridCom"
+ __type__ = "hook"
+ __version__ = "0.14"
- __config__ = [("activated", "bool", "Activated", False),
- ("https", "bool", "Enable HTTPS", False),
+ __config__ = [("https", "bool", "Enable HTTPS", False),
("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to stanard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """Alldebrid.com hook plugin"""
- __author_name__ = "Andy Voigt"
- __author_mail__ = "spamsales@online.de"
+ __license__ = "GPLv3"
+ __authors__ = [("Andy Voigt", "spamsales@online.de")]
def getHoster(self):
https = "https" if self.getConfig("https") else "http"
- page = getURL(https + "://www.alldebrid.com/api.php?action=get_host").replace("\"", "").strip()
+ page = getURL(https + "://www.alldebrid.com/api.php", get={'action': "get_host"}).replace("\"", "").strip()
return [x.strip() for x in page.split(",") if x.strip()]
diff --git a/module/plugins/hooks/BypassCaptcha.py b/module/plugins/hooks/BypassCaptcha.py
index 5ac117818..a32de7f42 100644
--- a/module/plugins/hooks/BypassCaptcha.py
+++ b/module/plugins/hooks/BypassCaptcha.py
@@ -1,73 +1,69 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-from thread import start_new_thread
from pycurl import FORM_FILE, LOW_SPEED_TIME
+from thread import start_new_thread
-from module.network.RequestFactory import getURL, getRequest
from module.network.HTTPRequest import BadHeader
-
+from module.network.RequestFactory import getURL, getRequest
from module.plugins.Hook import Hook
-PYLOAD_KEY = "4f771155b640970d5607f919a615bdefc67e7d32"
-
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"
- __version__ = "0.04"
- __type__ = "hook"
+ __name__ = "BypassCaptcha"
+ __type__ = "hook"
+ __version__ = "0.05"
- __config__ = [("activated", "bool", "Activated", False),
- ("force", "bool", "Force BC even if client is connected", False),
+ __config__ = [("force", "bool", "Force BC even if client is connected", False),
("passkey", "password", "Passkey", "")]
__description__ = """Send captchas to BypassCaptcha.com"""
- __author_name__ = ("RaNaN", "Godofdream", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "soilfcition@gmail.com", "zoidberg@mujmail.cz")
+ __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"
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
+
+
def setup(self):
- self.info = {}
+ self.info = {} #@TODO: Remove in 0.4.10
+
def getCredits(self):
- response = getURL(self.GETCREDITS_URL, post={"key": self.getConfig("passkey")})
+ res = getURL(self.GETCREDITS_URL, post={"key": self.getConfig("passkey")})
- data = dict([x.split(' ', 1) for x in response.splitlines()])
+ data = dict([x.split(' ', 1) for x in res.splitlines()])
return int(data['Left'])
+
def submit(self, captcha, captchaType="file", match=None):
req = getRequest()
@@ -75,31 +71,33 @@ class BypassCaptcha(Hook):
req.c.setopt(LOW_SPEED_TIME, 80)
try:
- response = req.load(self.SUBMIT_URL,
- post={"vendor_key": PYLOAD_KEY,
- "key": self.getConfig("passkey"),
- "gen_task_id": "1",
- "file": (FORM_FILE, captcha)},
- multipart=True)
+ 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 response.splitlines()])
+ data = dict([x.split(' ', 1) for x in res.splitlines()])
if not data or "Value" not in data:
- raise BypassCaptchaException(response)
+ raise BypassCaptchaException(res)
result = data['Value']
ticket = data['TaskId']
- self.logDebug("result %s : %s" % (ticket, result))
+ self.logDebug("Result %s : %s" % (ticket, result))
return ticket, result
+
def respond(self, ticket, success):
try:
- response = getURL(self.RESPOND_URL, post={"task_id": ticket, "key": self.getConfig("passkey"),
+ 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.", str(e))
+ self.logError(_("Could not send response"), e)
+
def newCaptchaTask(self, task):
if "service" in task.data:
@@ -121,16 +119,19 @@ class BypassCaptcha(Hook):
start_new_thread(self.processCaptcha, (task,))
else:
- self.logInfo("Your %s account has not enough credits" % self.__name__)
+ 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)
+
def processCaptcha(self, task):
c = task.captchaFile
try:
diff --git a/module/plugins/hooks/Captcha9kw.py b/module/plugins/hooks/Captcha9kw.py
index b4e3ad34b..33ad00c49 100755
--- a/module/plugins/hooks/Captcha9kw.py
+++ b/module/plugins/hooks/Captcha9kw.py
@@ -1,170 +1,261 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
from __future__ import with_statement
-from thread import start_new_thread
+import re
+
from base64 import b64encode
-import time
+from thread import start_new_thread
+from time import sleep
-from module.network.RequestFactory import getURL
from module.network.HTTPRequest import BadHeader
+from module.network.RequestFactory import getURL
from module.plugins.Hook import Hook
class Captcha9kw(Hook):
- __name__ = "Captcha9kw"
- __version__ = "0.09"
- __type__ = "hook"
-
- __config__ = [("activated", "bool", "Activated", False),
- ("force", "bool", "Force CT even if client is connected", True),
- ("https", "bool", "Enable HTTPS", False),
- ("confirm", "bool", "Confirm Captcha (Cost +6)", False),
- ("captchaperhour", "int", "Captcha per hour (max. 9999)", 9999),
- ("prio", "int", "Prio 1-10 (Cost +1-10)", 0),
- ("selfsolve", "bool",
- "If enabled and you have a 9kw client active only you will get your captcha to solve it (Selfsolve)",
- False),
- ("timeout", "int", "Timeout (max. 300)", 300),
- ("passkey", "password", "API key", "")]
+ __name__ = "Captcha9kw"
+ __type__ = "hook"
+ __version__ = "0.26"
+
+ __config__ = [("activated" , "bool" , "Activated" , True ),
+ ("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"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
- API_URL = "://www.9kw.eu/index.cgi"
+ API_URL = "http://www.9kw.eu/index.cgi"
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def setup(self):
- self.API_URL = "https" + self.API_URL if self.getConfig("https") else "http" + self.API_URL
- self.info = {}
+ self.info = {} #@TODO: Remove in 0.4.10
+ if self.getConfig("ssl"):
+ self.API_URL = self.API_URL.replace("http://", "https://")
- def getCredits(self):
- response = getURL(self.API_URL, get={"apikey": self.getConfig("passkey"), "pyload": "1", "source": "pyload",
- "action": "usercaptchaguthaben"})
- if response.isdigit():
- self.logInfo(_("%s credits left") % response)
- self.info['credits'] = credits = int(response)
+ 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(response)
+ self.logError(res)
return 0
- def processCaptcha(self, task):
- result = None
- with open(task.captchaFile, 'rb') as f:
- data = f.read()
+ def _processCaptcha(self, task):
+ try:
+ with open(task.captchaFile, 'rb') as f:
+ data = f.read()
+
+ except IOError, e:
+ self.logError(e)
+ return
+
data = b64encode(data)
- self.logDebug("%s : %s" % (task.captchaFile, data))
- if task.isPositional():
- mouse = 1
- else:
- mouse = 0
-
- response = getURL(self.API_URL, post={
- "apikey": self.getConfig("passkey"),
- "prio": self.getConfig("prio"),
- "confirm": self.getConfig("confirm"),
- "captchaperhour": self.getConfig("captchaperhour"),
- "maxtimeout": self.getConfig("timeout"),
- "selfsolve": self.getConfig("selfsolve"),
- "pyload": "1",
- "source": "pyload",
- "base64": "1",
- "mouse": mouse,
- "file-upload-01": data,
- "action": "usercaptchaupload"})
-
- if response.isdigit():
- self.logInfo(_("New CaptchaID from upload: %s : %s") % (response, task.captchaFile))
-
- for _ in xrange(1, 100, 1):
- response2 = getURL(self.API_URL, get={"apikey": self.getConfig("passkey"), "id": response,
- "pyload": "1", "source": "pyload",
- "action": "usercaptchacorrectdata"})
-
- if response2 != "":
+ mouse = 1 if task.isPositional() else 0
+ 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' : mouse,
+ 'file-upload-01': 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
- time.sleep(3)
+ self.logInfo(_("Captcha result for ticket %s: %s") % (res, result))
+
+ task.setResult(result)
- result = response2
- task.data['ticket'] = response
- self.logInfo("result %s : %s" % (response, result))
- task.setResult(result)
- else:
- self.logError("Bad upload: %s" % response)
- return False
def newCaptchaTask(self, task):
if not task.isTextual() and not task.isPositional():
- return False
+ return
if not self.getConfig("passkey"):
- return False
+ return
if self.core.isClientConnected() and not self.getConfig("force"):
- return False
+ return
- if self.getCredits() > 0:
- task.handler.append(self)
- task.setWaiting(self.getConfig("timeout"))
- start_new_thread(self.processCaptcha, (task,))
+ credits = self.getCredits()
- else:
- self.logError(_("Your Captcha 9kw.eu Account has not enough credits"))
+ if not credits:
+ self.logError(_("Your captcha 9kw.eu account has not enough credits"))
+ return
- def captchaCorrect(self, task):
- if "ticket" in task.data:
+ queue = min(self.getConfig("queue"), 999)
+ timeout = min(max(self.getConfig("timeout"), 300), 3999)
+ pluginname = re.search(r'_([^_]*)_\d+.\w+', task.captchaFile).group(1)
- try:
- response = getURL(self.API_URL,
- post={"action": "usercaptchacorrectback",
- "apikey": self.getConfig("passkey"),
- "api_key": self.getConfig("passkey"),
- "correct": "1",
- "pyload": "1",
- "source": "pyload",
- "id": task.data['ticket']})
- self.logInfo("Request correct: %s" % response)
+ 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
- except BadHeader, e:
- self.logError("Could not send correct request.", str(e))
+ sleep(10)
else:
- self.logError("No CaptchaID for correct request (task %s) found." % task)
+ self.fail(_("Too many captchas in queue"))
- def captchaInvalid(self, task):
- if "ticket" in task.data:
+ for opt in str(self.getConfig("hoster_options").split('|')):
+ details = map(str.strip, opt.split(':'))
- try:
- response = getURL(self.API_URL,
- post={"action": "usercaptchacorrectback",
- "apikey": self.getConfig("passkey"),
- "api_key": self.getConfig("passkey"),
- "correct": "2",
- "pyload": "1",
- "source": "pyload",
- "id": task.data['ticket']})
- self.logInfo("Request refund: %s" % response)
+ if not details or details[0].lower() != pluginname.lower():
+ continue
- except BadHeader, e:
- self.logError("Could not send refund request.", str(e))
+ 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.logError("No CaptchaID for not correct request (task %s) found." % task)
+ 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
index 54dfbe4d6..b6e38d8bb 100644
--- a/module/plugins/hooks/CaptchaBrotherhood.py
+++ b/module/plugins/hooks/CaptchaBrotherhood.py
@@ -1,28 +1,18 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
from __future__ import with_statement
-from thread import start_new_thread
-
-import pycurl
import StringIO
-from urllib import urlencode
+import pycurl
+
+try:
+ from PIL import Image
+except ImportError:
+ import Image
+
+from thread import start_new_thread
from time import sleep
-from PIL import Image
+from urllib import urlencode
from module.network.RequestFactory import getURL, getRequest
from module.plugins.Hook import Hook
@@ -33,47 +23,58 @@ 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"
- __version__ = "0.05"
- __type__ = "hook"
+ __name__ = "CaptchaBrotherhood"
+ __type__ = "hook"
+ __version__ = "0.06"
- __config__ = [("activated", "bool", "Activated", False),
- ("username", "str", "Username", ""),
+ __config__ = [("username", "str", "Username", ""),
("force", "bool", "Force CT even if client is connected", False),
("passkey", "password", "Password", "")]
__description__ = """Send captchas to CaptchaBrotherhood.com"""
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
API_URL = "http://www.captchabrotherhood.com/"
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
+
+
def setup(self):
- self.info = {}
+ self.info = {} #@TODO: Remove in 0.4.10
+
def getCredits(self):
- response = getURL(self.API_URL + "askCredits.aspx",
- get={"username": self.getConfig("username"), "password": self.getConfig("passkey")})
- if not response.startswith("OK"):
- raise CaptchaBrotherhoodException(response)
+ 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(response[3:])
+ 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)
@@ -105,34 +106,36 @@ class CaptchaBrotherhood(Hook):
try:
req.c.perform()
- response = req.getResponse()
+ res = req.getResponse()
except Exception, e:
raise CaptchaBrotherhoodException("Submit captcha image failed")
req.close()
- if not response.startswith("OK"):
- raise CaptchaBrotherhoodException(response[1])
+ if not res.startswith("OK"):
+ raise CaptchaBrotherhoodException(res[1])
- ticket = response[3:]
+ ticket = res[3:]
- for _ in xrange(15):
+ for _i in xrange(15):
sleep(5)
- response = self.get_api("askCaptchaResult", ticket)
- if response.startswith("OK-answered"):
- return ticket, response[12:]
+ res = self.get_api("askCaptchaResult", ticket)
+ if res.startswith("OK-answered"):
+ return ticket, res[12:]
raise CaptchaBrotherhoodException("No solution received in time")
+
def get_api(self, api, ticket):
- response = getURL("%s%s.aspx" % (self.API_URL, api),
+ res = getURL("%s%s.aspx" % (self.API_URL, api),
get={"username": self.getConfig("username"),
"password": self.getConfig("passkey"),
"captchaID": ticket})
- if not response.startswith("OK"):
- raise CaptchaBrotherhoodException("Unknown response: %s" % response)
+ if not res.startswith("OK"):
+ raise CaptchaBrotherhoodException("Unknown response: %s" % res)
+
+ return res
- return response
def newCaptchaTask(self, task):
if "service" in task.data:
@@ -153,11 +156,13 @@ class CaptchaBrotherhood(Hook):
task.setWaiting(100)
start_new_thread(self.processCaptcha, (task,))
else:
- self.logInfo("Your CaptchaBrotherhood Account has not enough credits")
+ self.logInfo(_("Your CaptchaBrotherhood Account has not enough credits"))
+
def captchaInvalid(self, task):
if task.data['service'] == self.__name__ and "ticket" in task.data:
- response = self.get_api("complainCaptcha", task.data['ticket'])
+ res = self.get_api("complainCaptcha", task.data['ticket'])
+
def processCaptcha(self, task):
c = task.captchaFile
diff --git a/module/plugins/hooks/Checksum.py b/module/plugins/hooks/Checksum.py
index a51eb4b47..8d9f8f981 100644
--- a/module/plugins/hooks/Checksum.py
+++ b/module/plugins/hooks/Checksum.py
@@ -1,29 +1,16 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from __future__ import with_statement
+
import hashlib
+import re
import zlib
+
from os import remove
from os.path import getsize, isfile, splitext
-import re
-from module.utils import save_join, fs_encode
from module.plugins.Hook import Hook
+from module.utils import save_join, fs_encode
def computeChecksum(local_file, algorithm):
@@ -31,7 +18,7 @@ def computeChecksum(local_file, algorithm):
h = getattr(hashlib, algorithm)()
with open(local_file, 'rb') as f:
- for chunk in iter(lambda: f.read(128 * h.block_size), b''):
+ for chunk in iter(lambda: f.read(128 * h.block_size), ''):
h.update(chunk)
return h.hexdigest()
@@ -41,7 +28,7 @@ def computeChecksum(local_file, algorithm):
last = 0
with open(local_file, 'rb') as f:
- for chunk in iter(lambda: f.read(8192), b''):
+ for chunk in iter(lambda: f.read(8192), ''):
last = hf(chunk, last)
return "%x" % last
@@ -51,30 +38,39 @@ def computeChecksum(local_file, algorithm):
class Checksum(Hook):
- __name__ = "Checksum"
- __version__ = "0.12"
- __type__ = "hook"
+ __name__ = "Checksum"
+ __type__ = "hook"
+ __version__ = "0.15"
- __config__ = [("activated", "bool", "Activated", False),
+ __config__ = [("check_checksum", "bool", "Check checksum? (If False only size will be verified)", True),
("check_action", "fail;retry;nothing", "What to do if check fails?", "retry"),
("max_tries", "int", "Number of retries", 2),
("retry_action", "fail;nothing", "What to do if all retries fail?", "fail"),
("wait_time", "int", "Time to wait before each retry (seconds)", 1)]
__description__ = """Verify downloaded file size and checksum"""
- __author_name__ = ("zoidberg", "Walter Purcaro")
- __author_mail__ = ("zoidberg@mujmail.cz", "vuolter@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("Walter Purcaro", "vuolter@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
+
methods = {'sfv': 'crc32', 'crc': 'crc32', 'hash': 'md5'}
- regexps = {'sfv': r'^(?P<name>[^;].+)\s+(?P<hash>[0-9A-Fa-f]{8})$',
- 'md5': r'^(?P<name>[0-9A-Fa-f]{32}) (?P<file>.+)$',
- 'crc': r'filename=(?P<name>.+)\nsize=(?P<size>\d+)\ncrc32=(?P<hash>[0-9A-Fa-f]{8})$',
- 'default': r'^(?P<hash>[0-9A-Fa-f]+)\s+\*?(?P<name>.+)$'}
+ regexps = {'sfv': r'^(?P<NAME>[^;].+)\s+(?P<HASH>[0-9A-Fa-f]{8})$',
+ 'md5': r'^(?P<NAME>[0-9A-Fa-f]{32}) (?P<FILE>.+)$',
+ 'crc': r'filename=(?P<NAME>.+)\nsize=(?P<SIZE>\d+)\ncrc32=(?P<HASH>[0-9A-Fa-f]{8})$',
+ 'default': r'^(?P<HASH>[0-9A-Fa-f]+)\s+\*?(?P<NAME>.+)$'}
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def coreReady(self):
- if not self.config['general']['checksum']:
- self.logInfo("Checksum validation is disabled in general configuration")
+ if not self.getConfig("check_checksum"):
+ self.logInfo(_("Checksum validation is disabled in plugin configuration"))
+
def setup(self):
self.algorithms = sorted(
@@ -82,6 +78,7 @@ class Checksum(Hook):
self.algorithms.extend(["crc32", "adler32"])
self.formats = self.algorithms + ["sfv", "crc", "hash"]
+
def downloadFinished(self, pyfile):
"""
Compute checksum for the downloaded file and compare it with the hash provided by the hoster.
@@ -89,10 +86,15 @@ class Checksum(Hook):
a) if known, the exact filesize in bytes (e.g. "size": 123456789)
b) hexadecimal hash string with algorithm name as key (e.g. "md5": "d76505d0869f9f928a17d42d66326307")
"""
- if hasattr(pyfile.plugin, "check_data") and (isinstance(pyfile.plugin.check_data, dict)):
+ if hasattr(pyfile.plugin, "check_data") and isinstance(pyfile.plugin.check_data, dict):
data = pyfile.plugin.check_data.copy()
- elif hasattr(pyfile.plugin, "api_data") and (isinstance(pyfile.plugin.api_data, dict)):
+
+ elif hasattr(pyfile.plugin, "api_data") and isinstance(pyfile.plugin.api_data, dict):
data = pyfile.plugin.api_data.copy()
+
+ # elif hasattr(pyfile.plugin, "info") and isinstance(pyfile.plugin.info, dict):
+ # data = pyfile.plugin.info.copy()
+
else:
return
@@ -113,12 +115,12 @@ class Checksum(Hook):
api_size = int(data['size'])
file_size = getsize(local_file)
if api_size != file_size:
- self.logWarning("File %s has incorrect size: %d B (%d expected)" % (pyfile.name, file_size, api_size))
+ self.logWarning(_("File %s has incorrect size: %d B (%d expected)") % (pyfile.name, file_size, api_size))
self.checkFailed(pyfile, local_file, "Incorrect file size")
del data['size']
# validate checksum
- if data and self.config['general']['checksum']:
+ if data and self.getConfig("check_checksum"):
if "checksum" in data:
data['md5'] = data['checksum']
@@ -127,17 +129,18 @@ class Checksum(Hook):
checksum = computeChecksum(local_file, key.replace("-", "").lower())
if checksum:
if checksum == data[key].lower():
- self.logInfo('File integrity of "%s" verified by %s checksum (%s).' %
+ self.logInfo(_('File integrity of "%s" verified by %s checksum (%s)') %
(pyfile.name, key.upper(), checksum))
break
else:
- self.logWarning("%s checksum for file %s does not match (%s != %s)" %
+ self.logWarning(_("%s checksum for file %s does not match (%s != %s)") %
(key.upper(), pyfile.name, checksum, data[key]))
self.checkFailed(pyfile, local_file, "Checksums do not match")
else:
- self.logWarning("Unsupported hashing algorithm: %s" % key.upper())
+ self.logWarning(_("Unsupported hashing algorithm"), key.upper())
else:
- self.logWarning("Unable to validate checksum for file %s" % pyfile.name)
+ self.logWarning(_("Unable to validate checksum for file: ") + pyfile.name)
+
def checkFailed(self, pyfile, local_file, msg):
check_action = self.getConfig("check_action")
@@ -147,26 +150,26 @@ class Checksum(Hook):
if pyfile.plugin.retries < max_tries:
if local_file:
remove(local_file)
- pyfile.plugin.retry(max_tries=max_tries, wait_time=self.getConfig("wait_time"), reason=msg)
+ pyfile.plugin.retry(max_tries, self.getConfig("wait_time"), msg)
elif retry_action == "nothing":
return
elif check_action == "nothing":
return
pyfile.plugin.fail(reason=msg)
+
def packageFinished(self, pypack):
download_folder = save_join(self.config['general']['download_folder'], pypack.folder, "")
for link in pypack.getChildren().itervalues():
file_type = splitext(link['name'])[1][1:].lower()
- #self.logDebug(link, file_type)
if file_type not in self.formats:
continue
hash_file = fs_encode(save_join(download_folder, link['name']))
if not isfile(hash_file):
- self.logWarning("File not found: %s" % link['name'])
+ self.logWarning(_("File not found"), link['name'])
continue
with open(hash_file) as f:
@@ -176,12 +179,12 @@ class Checksum(Hook):
data = m.groupdict()
self.logDebug(link['name'], data)
- local_file = fs_encode(save_join(download_folder, data['name']))
+ local_file = fs_encode(save_join(download_folder, data['NAME']))
algorithm = self.methods.get(file_type, file_type)
checksum = computeChecksum(local_file, algorithm)
- if checksum == data['hash']:
- self.logInfo('File integrity of "%s" verified by %s checksum (%s).' %
- (data['name'], algorithm, checksum))
+ if checksum == data['HASH']:
+ self.logInfo(_('File integrity of "%s" verified by %s checksum (%s)') %
+ (data['NAME'], algorithm, checksum))
else:
- self.logWarning("%s checksum for file %s does not match (%s != %s)" %
- (algorithm, data['name'], checksum, data['hash']))
+ self.logWarning(_("%s checksum for file %s does not match (%s != %s)") %
+ (algorithm, data['NAME'], checksum, data['HASH']))
diff --git a/module/plugins/hooks/ClickAndLoad.py b/module/plugins/hooks/ClickAndLoad.py
index 3c47d30ce..04aac2f10 100644
--- a/module/plugins/hooks/ClickAndLoad.py
+++ b/module/plugins/hooks/ClickAndLoad.py
@@ -1,53 +1,11 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import socket
import thread
from module.plugins.Hook import Hook
-class ClickAndLoad(Hook):
- __name__ = "ClickAndLoad"
- __version__ = "0.22"
- __type__ = "hook"
-
- __config__ = [("activated", "bool", "Activated", True),
- ("extern", "bool", "Allow external link adding", False)]
-
- __description__ = """Gives abillity to use jd's click and load. depends on webinterface"""
- __author_name__ = ("RaNaN", "mkaay")
- __author_mail__ = ("RaNaN@pyload.de", "mkaay@mkaay.de")
-
-
- def coreReady(self):
- self.port = int(self.config['webinterface']['port'])
- if self.config['webinterface']['activated']:
- try:
- if self.getConfig("extern"):
- ip = "0.0.0.0"
- else:
- ip = "127.0.0.1"
-
- thread.start_new_thread(proxy, (self, ip, self.port, 9666))
- except:
- self.logError("ClickAndLoad port already in use.")
-
-
def proxy(self, *settings):
thread.start_new_thread(server, (self,) + settings)
lock = thread.allocate_lock()
@@ -89,3 +47,31 @@ def forward(source, destination):
else:
#source.shutdown(socket.SHUT_RD)
destination.shutdown(socket.SHUT_WR)
+
+
+class ClickAndLoad(Hook):
+ __name__ = "ClickAndLoad"
+ __type__ = "hook"
+ __version__ = "0.24"
+
+ __config__ = [("activated", "bool", "Activated", True),
+ ("extern", "bool", "Allow external link adding", False)]
+
+ __description__ = """Click'N'Load hook plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.de"),
+ ("mkaay", "mkaay@mkaay.de")]
+
+
+ def coreReady(self):
+ self.port = int(self.config['webinterface']['port'])
+ if self.config['webinterface']['activated']:
+ try:
+ if self.getConfig("extern"):
+ ip = "0.0.0.0"
+ else:
+ ip = "127.0.0.1"
+
+ thread.start_new_thread(proxy, (self, ip, self.port, 9666))
+ except:
+ self.logError(_("ClickAndLoad port already in use"))
diff --git a/module/plugins/hooks/DeathByCaptcha.py b/module/plugins/hooks/DeathByCaptcha.py
index 64ed2280f..f03ac4567 100644
--- a/module/plugins/hooks/DeathByCaptcha.py
+++ b/module/plugins/hooks/DeathByCaptcha.py
@@ -1,31 +1,18 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
from __future__ import with_statement
-from thread import start_new_thread
+import re
+
+from base64 import b64encode
from pycurl import FORM_FILE, HTTPHEADER
+from thread import start_new_thread
from time import sleep
-from base64 import b64encode
-import re
-from module.network.RequestFactory import getRequest
+from module.common.json_layer import json_loads
from module.network.HTTPRequest import BadHeader
+from module.network.RequestFactory import getRequest
from module.plugins.Hook import Hook
-from module.common.json_layer import json_loads
class DeathByCaptchaException(Exception):
@@ -38,44 +25,56 @@ class DeathByCaptchaException(Exception):
'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"
- __version__ = "0.03"
- __type__ = "hook"
+ __name__ = "DeathByCaptcha"
+ __type__ = "hook"
+ __version__ = "0.04"
- __config__ = [("activated", "bool", "Activated", False),
- ("username", "str", "Username", ""),
+ __config__ = [("username", "str", "Username", ""),
("passkey", "password", "Password", ""),
("force", "bool", "Force DBC even if client is connected", False)]
__description__ = """Send captchas to DeathByCaptcha.com"""
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
API_URL = "http://api.dbcapi.me/api/"
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
+
+
def setup(self):
- self.info = {}
+ self.info = {} #@TODO: Remove in 0.4.10
+
def call_api(self, api="captcha", post=False, multipart=False):
req = getRequest()
@@ -87,18 +86,18 @@ class DeathByCaptcha(Hook):
post.update({"username": self.getConfig("username"),
"password": self.getConfig("passkey")})
- response = None
+ res = None
try:
json = req.load("%s%s" % (self.API_URL, api),
post=post,
multipart=multipart)
self.logDebug(json)
- response = json_loads(json)
+ res = json_loads(json)
- if "error" in response:
- raise DeathByCaptchaException(response['error'])
- elif "status" not in response:
- raise DeathByCaptchaException(str(response))
+ if "error" in res:
+ raise DeathByCaptchaException(res['error'])
+ elif "status" not in res:
+ raise DeathByCaptchaException(str(res))
except BadHeader, e:
if 403 == e.code:
@@ -115,27 +114,30 @@ class DeathByCaptcha(Hook):
finally:
req.close()
- return response
+ return res
+
def getCredits(self):
- response = self.call_api("user", True)
+ res = self.call_api("user", True)
- if 'is_banned' in response and response['is_banned']:
+ if 'is_banned' in res and res['is_banned']:
raise DeathByCaptchaException('banned')
- elif 'balance' in response and 'rate' in response:
- self.info.update(response)
+ elif 'balance' in res and 'rate' in res:
+ self.info.update(res)
else:
- raise DeathByCaptchaException(response)
+ raise DeathByCaptchaException(res)
+
def getStatus(self):
- response = self.call_api("status", False)
+ res = self.call_api("status", False)
- if 'is_service_overloaded' in response and response['is_service_overloaded']:
+ if 'is_service_overloaded' in res and res['is_service_overloaded']:
raise DeathByCaptchaException('service-overload')
+
def submit(self, captcha, captchaType="file", match=None):
- #workaround multipart-post bug in HTTPRequest.py
- if re.match("^[A-Za-z0-9]*$", self.getConfig("passkey")):
+ #workaround multipart-post bug in HTTPRequest.py
+ if re.match("^\w*$", self.getConfig("passkey")):
multipart = True
data = (FORM_FILE, captcha)
else:
@@ -144,25 +146,26 @@ class DeathByCaptcha(Hook):
data = f.read()
data = "base64:" + b64encode(data)
- response = self.call_api("captcha", {"captchafile": data}, multipart)
+ res = self.call_api("captcha", {"captchafile": data}, multipart)
- if "captcha" not in response:
- raise DeathByCaptchaException(response)
- ticket = response['captcha']
+ if "captcha" not in res:
+ raise DeathByCaptchaException(res)
+ ticket = res['captcha']
- for _ in xrange(24):
+ for _i in xrange(24):
sleep(5)
- response = self.call_api("captcha/%d" % ticket, False)
- if response['text'] and response['is_correct']:
+ res = self.call_api("captcha/%d" % ticket, False)
+ if res['text'] and res['is_correct']:
break
else:
raise DeathByCaptchaException('timed-out')
- result = response['text']
- self.logDebug("result %s : %s" % (ticket, result))
+ result = res['text']
+ self.logDebug("Result %s : %s" % (ticket, result))
return ticket, result
+
def newCaptchaTask(self, task):
if "service" in task.data:
return False
@@ -184,8 +187,9 @@ class DeathByCaptcha(Hook):
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))
+ 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)
@@ -193,15 +197,19 @@ class DeathByCaptcha(Hook):
task.setWaiting(180)
start_new_thread(self.processCaptcha, (task,))
+
def captchaInvalid(self, task):
if task.data['service'] == self.__name__ and "ticket" in task.data:
try:
- response = self.call_api("captcha/%d/report" % task.data['ticket'], True)
+ res = self.call_api("captcha/%d/report" % task.data['ticket'], True)
+
except DeathByCaptchaException, e:
self.logError(e.getDesc())
+
except Exception, e:
self.logError(e)
+
def processCaptcha(self, task):
c = task.captchaFile
try:
diff --git a/module/plugins/hooks/DebridItaliaCom.py b/module/plugins/hooks/DebridItaliaCom.py
index 1a081da7a..e31bc98d7 100644
--- a/module/plugins/hooks/DebridItaliaCom.py
+++ b/module/plugins/hooks/DebridItaliaCom.py
@@ -1,43 +1,26 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.MultiHoster import MultiHoster
-
-
-class DebridItaliaCom(MultiHoster):
- __name__ = "DebridItaliaCom"
- __version__ = "0.07"
- __type__ = "hook"
-
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+
+import re
+
+from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
+
+
+class DebridItaliaCom(MultiHook):
+ __name__ = "DebridItaliaCom"
+ __type__ = "hook"
+ __version__ = "0.10"
+
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to standard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """Debriditalia.com hook plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
def getHoster(self):
- return ["netload.in", "hotfile.com", "rapidshare.com", "multiupload.com",
- "uploading.com", "megashares.com", "crocko.com", "filepost.com",
- "bitshare.com", "share-links.biz", "putlocker.com", "uploaded.to",
- "speedload.org", "rapidgator.net", "likeupload.net", "cyberlocker.ch",
- "depositfiles.com", "extabit.com", "filefactory.com", "sharefiles.co",
- "ryushare.com", "tusfiles.net", "nowvideo.co", "cloudzer.net", "letitbit.net",
- "easybytez.com", "uptobox.com", "ddlstorage.com"]
+ return getURL("http://debriditalia.com/api.php", get={'hosts': ""}).replace('"', '').split(',')
diff --git a/module/plugins/hooks/DeleteFinished.py b/module/plugins/hooks/DeleteFinished.py
index 1c80facc9..5d2b78d50 100644
--- a/module/plugins/hooks/DeleteFinished.py
+++ b/module/plugins/hooks/DeleteFinished.py
@@ -1,36 +1,24 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.database import style
from module.plugins.Hook import Hook
class DeleteFinished(Hook):
- __name__ = "DeleteFinished"
- __version__ = "1.09"
- __type__ = "hook"
+ __name__ = "DeleteFinished"
+ __type__ = "hook"
+ __version__ = "1.11"
__config__ = [('activated', 'bool', 'Activated', 'False'),
('interval', 'int', 'Delete every (hours)', '72'),
('deloffline', 'bool', 'Delete packages with offline links', 'False')]
__description__ = """Automatically delete all finished packages from queue"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ # event_list = ["pluginConfigChanged"]
## overwritten methods ##
@@ -38,47 +26,54 @@ class DeleteFinished(Hook):
if not self.info['sleep']:
deloffline = self.getConfig('deloffline')
mode = '0,1,4' if deloffline else '0,4'
- msg = 'delete all finished packages in queue list (%s packages with offline links)'
- self.logInfo(msg % ('including' if deloffline else 'excluding'))
+ msg = _('delete all finished packages in queue list (%s packages with offline links)')
+ self.logInfo(msg % (_('including') if deloffline else _('excluding')))
self.deleteFinished(mode)
self.info['sleep'] = True
self.addEvent('packageFinished', self.wakeup)
+
def pluginConfigChanged(self, plugin, name, value):
- if name == 'interval' and value != self.interval:
+ if name == "interval" and value != self.interval:
self.interval = value * 3600
self.initPeriodical()
+
def unload(self):
self.removeEvent('packageFinished', self.wakeup)
+
def coreReady(self):
self.info = {'sleep': True}
interval = self.getConfig('interval')
- self.pluginConfigChanged('DeleteFinished', 'interval', interval)
+ self.pluginConfigChanged(self.__name__, 'interval', interval)
self.addEvent('packageFinished', self.wakeup)
+
## own methods ##
@style.queue
def deleteFinished(self, mode):
self.c.execute('DELETE FROM packages WHERE NOT EXISTS(SELECT 1 FROM links WHERE package=packages.id AND status NOT IN (%s))' % mode)
self.c.execute('DELETE FROM links WHERE NOT EXISTS(SELECT 1 FROM packages WHERE id=links.package)')
+
def wakeup(self, pypack):
self.removeEvent('packageFinished', self.wakeup)
self.info['sleep'] = False
+
## event managing ##
def addEvent(self, event, func):
"""Adds an event listener for event name"""
if event in self.m.events:
if func in self.m.events[event]:
- self.logDebug('Function already registered %s' % func)
+ self.logDebug("Function already registered", func)
else:
self.m.events[event].append(func)
else:
self.m.events[event] = [func]
+
def setup(self):
self.m = self.manager
self.removeEvent = self.m.removeEvent
diff --git a/module/plugins/hooks/DownloadScheduler.py b/module/plugins/hooks/DownloadScheduler.py
index 070c0634e..4996e212d 100644
--- a/module/plugins/hooks/DownloadScheduler.py
+++ b/module/plugins/hooks/DownloadScheduler.py
@@ -1,47 +1,40 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-
- Original idea by new.cze
-"""
-
import re
+
from time import localtime
from module.plugins.Hook import Hook
class DownloadScheduler(Hook):
- __name__ = "DownloadScheduler"
- __version__ = "0.21"
- __type__ = "hook"
+ __name__ = "DownloadScheduler"
+ __type__ = "hook"
+ __version__ = "0.22"
- __config__ = [("activated", "bool", "Activated", False),
- ("timetable", "str", "List time periods as hh:mm full or number(kB/s)",
+ __config__ = [("timetable", "str", "List time periods as hh:mm full or number(kB/s)",
"0:00 full, 7:00 250, 10:00 0, 17:00 150"),
("abort", "bool", "Abort active downloads when start period with speed 0", False)]
__description__ = """Download Scheduler"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def setup(self):
self.cb = None # callback to scheduler job; will be by removed hookmanager when hook unloaded
+
def coreReady(self):
self.updateSchedule()
+
def updateSchedule(self, schedule=None):
if schedule is None:
schedule = self.getConfig("timetable")
@@ -49,7 +42,7 @@ class DownloadScheduler(Hook):
schedule = re.findall("(\d{1,2}):(\d{2})[\s]*(-?\d+)",
schedule.lower().replace("full", "-1").replace("none", "0"))
if not schedule:
- self.logError("Invalid schedule")
+ self.logError(_("Invalid schedule"))
return
t0 = localtime()
@@ -69,10 +62,11 @@ class DownloadScheduler(Hook):
self.core.scheduler.removeJob(self.cb)
self.cb = self.core.scheduler.addJob(next_time, self.updateSchedule, threaded=False)
+
def setDownloadSpeed(self, speed):
if speed == 0:
abort = self.getConfig("abort")
- self.logInfo("Stopping download server. (Running downloads will %sbe aborted.)" % ('' if abort else 'not '))
+ self.logInfo(_("Stopping download server. (Running downloads will %sbe aborted.)") % '' if abort else _('not '))
self.core.api.pauseServer()
if abort:
self.core.api.stopAllDownloads()
@@ -80,10 +74,10 @@ class DownloadScheduler(Hook):
self.core.api.unpauseServer()
if speed > 0:
- self.logInfo("Setting download speed to %d kB/s" % speed)
+ self.logInfo(_("Setting download speed to %d kB/s") % speed)
self.core.api.setConfigValue("download", "limit_speed", 1)
self.core.api.setConfigValue("download", "max_speed", speed)
else:
- self.logInfo("Setting download speed to FULL")
+ self.logInfo(_("Setting download speed to FULL"))
self.core.api.setConfigValue("download", "limit_speed", 0)
self.core.api.setConfigValue("download", "max_speed", -1)
diff --git a/module/plugins/hooks/EasybytezCom.py b/module/plugins/hooks/EasybytezCom.py
index 1cf5e40ae..0dab2a7fe 100644
--- a/module/plugins/hooks/EasybytezCom.py
+++ b/module/plugins/hooks/EasybytezCom.py
@@ -2,21 +2,20 @@
import re
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class EasybytezCom(MultiHoster):
- __name__ = "EasybytezCom"
- __version__ = "0.03"
- __type__ = "hook"
+class EasybytezCom(MultiHook):
+ __name__ = "EasybytezCom"
+ __type__ = "hook"
+ __version__ = "0.04"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", "")]
__description__ = """EasyBytez.com hook plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
def getHoster(self):
@@ -24,14 +23,17 @@ class EasybytezCom(MultiHoster):
user = self.account.selectAccount()[0]
try:
- req = self.account.getAccountRequest(user)
+ req = self.account.getAccountRequest(user)
page = req.load("http://www.easybytez.com")
- m = re.search(r'</textarea>\s*Supported sites:(.*)', page)
- return m.group(1).split(',')
+ hosters = re.search(r'</textarea>\s*Supported sites:(.*)', page).group(1).split(',')
+
except Exception, e:
+ self.logWarning(_("Unable to load supported hoster list, using last known"))
self.logDebug(e)
- self.logWarning("Unable to load supported hoster list, using last known")
- return ["bitshare.com", "crocko.com", "ddlstorage.com", "depositfiles.com", "extabit.com", "hotfile.com",
- "mediafire.com", "netload.in", "rapidgator.net", "rapidshare.com", "uploading.com", "uload.to",
- "uploaded.to"]
+
+ hosters = ["bitshare.com", "crocko.com", "ddlstorage.com", "depositfiles.com", "extabit.com", "hotfile.com",
+ "mediafire.com", "netload.in", "rapidgator.net", "rapidshare.com", "uploading.com", "uload.to",
+ "uploaded.to"]
+ finally:
+ return hosters
diff --git a/module/plugins/hooks/Ev0InFetcher.py b/module/plugins/hooks/Ev0InFetcher.py
deleted file mode 100644
index 3a98abbf7..000000000
--- a/module/plugins/hooks/Ev0InFetcher.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-from time import mktime, time
-
-from module.lib import feedparser
-from module.plugins.Hook import Hook
-
-
-class Ev0InFetcher(Hook):
- __name__ = "Ev0InFetcher"
- __version__ = "0.21"
- __type__ = "hook"
-
- __config__ = [("activated", "bool", "Activated", False),
- ("interval", "int", "Check interval in minutes", 10),
- ("queue", "bool", "Move new shows directly to Queue", False),
- ("shows", "str", "Shows to check for (comma seperated)", ""),
- ("quality", "xvid;x264;rmvb", "Video Format", "xvid"),
- ("hoster", "str", "Hoster to use (comma seperated)",
- "NetloadIn,RapidshareCom,MegauploadCom,HotfileCom")]
-
- __description__ = """Checks rss feeds for Ev0.in"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
-
-
- def setup(self):
- self.interval = self.getConfig("interval") * 60
-
- def filterLinks(self, links):
- results = self.core.pluginManager.parseUrls(links)
- sortedLinks = {}
-
- for url, hoster in results:
- if hoster not in sortedLinks:
- sortedLinks[hoster] = []
- sortedLinks[hoster].append(url)
-
- for h in self.getConfig("hoster").split(","):
- try:
- return sortedLinks[h.strip()]
- except:
- continue
- return []
-
-
- def periodical(self):
-
- def normalizefiletitle(filename):
- filename = filename.replace('.', ' ')
- filename = filename.replace('_', ' ')
- filename = filename.lower()
- return filename
-
- shows = [s.strip() for s in self.getConfig("shows").split(",")]
-
- feed = feedparser.parse("http://feeds.feedburner.com/ev0in/%s?format=xml" % self.getConfig("quality"))
-
- showStorage = {}
- for show in shows:
- showStorage[show] = int(self.getStorage("show_%s_lastfound" % show, 0))
-
- found = False
- for item in feed['items']:
- for show, lastfound in showStorage.iteritems():
- if show.lower() in normalizefiletitle(item['title']) and lastfound < int(mktime(item.date_parsed)):
- links = self.filterLinks(item['description'].split("<br />"))
- packagename = item['title'].encode("utf-8")
- self.logInfo("Ev0InFetcher: new episode '%s' (matched '%s')" % (packagename, show))
- self.core.api.addPackage(packagename, links, 1 if self.getConfig("queue") else 0)
- self.setStorage("show_%s_lastfound" % show, int(mktime(item.date_parsed)))
- found = True
- if not found:
- #self.logDebug("Ev0InFetcher: no new episodes found")
- pass
-
- for show, lastfound in self.getStorage().iteritems():
- if int(lastfound) > 0 and int(lastfound) + (3600 * 24 * 30) < int(time()):
- self.delStorage("show_%s_lastfound" % show)
- self.logDebug("Ev0InFetcher: cleaned '%s' record" % show)
diff --git a/module/plugins/hooks/ExpertDecoders.py b/module/plugins/hooks/ExpertDecoders.py
index 9e151f8f6..54de8eb53 100644
--- a/module/plugins/hooks/ExpertDecoders.py
+++ b/module/plugins/hooks/ExpertDecoders.py
@@ -1,62 +1,55 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
from __future__ import with_statement
-from thread import start_new_thread
+from base64 import b64encode
from pycurl import LOW_SPEED_TIME
+from thread import start_new_thread
from uuid import uuid4
-from base64 import b64encode
-from module.network.RequestFactory import getURL, getRequest
from module.network.HTTPRequest import BadHeader
-
+from module.network.RequestFactory import getURL, getRequest
from module.plugins.Hook import Hook
class ExpertDecoders(Hook):
- __name__ = "ExpertDecoders"
- __version__ = "0.01"
- __type__ = "hook"
+ __name__ = "ExpertDecoders"
+ __type__ = "hook"
+ __version__ = "0.03"
- __config__ = [("activated", "bool", "Activated", False),
- ("force", "bool", "Force CT even if client is connected", False),
+ __config__ = [("force", "bool", "Force CT even if client is connected", False),
("passkey", "password", "Access key", "")]
__description__ = """Send captchas to expertdecoders.com"""
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
API_URL = "http://www.fasttypers.org/imagepost.ashx"
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
+
+
def setup(self):
- self.info = {}
+ self.info = {} #@TODO: Remove in 0.4.10
+
def getCredits(self):
- response = getURL(self.API_URL, post={"key": self.getConfig("passkey"), "action": "balance"})
+ res = getURL(self.API_URL, post={"key": self.getConfig("passkey"), "action": "balance"})
- if response.isdigit():
- self.logInfo(_("%s credits left") % response)
- self.info['credits'] = credits = int(response)
+ if res.isdigit():
+ self.logInfo(_("%s credits left") % res)
+ self.info['credits'] = credits = int(res)
return credits
else:
- self.logError(response)
+ self.logError(res)
return 0
+
def processCaptcha(self, task):
task.data['ticket'] = ticket = uuid4()
result = None
@@ -64,21 +57,21 @@ class ExpertDecoders(Hook):
with open(task.captchaFile, 'rb') as f:
data = f.read()
data = b64encode(data)
- #self.logDebug("%s: %s : %s" % (ticket, task.captchaFile, data))
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"),
+ result = req.load(self.API_URL, post={"action": "upload", "key": self.getConfig("passkey"),
"file": data, "gen_task_id": ticket})
finally:
req.close()
- self.logDebug("result %s : %s" % (ticket, result))
+ self.logDebug("Result %s : %s" % (ticket, result))
task.setResult(result)
+
def newCaptchaTask(self, task):
if not task.isTextual():
return False
@@ -97,13 +90,14 @@ class ExpertDecoders(Hook):
else:
self.logInfo(_("Your ExpertDecoders Account has not enough credits"))
+
def captchaInvalid(self, task):
if "ticket" in task.data:
try:
- response = getURL(self.API_URL, post={"action": "refund", "key": self.getConfig("passkey"),
- "gen_task_id": task.data['ticket']})
- self.logInfo("Request refund: %s" % response)
+ 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.", str(e))
+ self.logError(_("Could not send refund request"), e)
diff --git a/module/plugins/hooks/ExternalScripts.py b/module/plugins/hooks/ExternalScripts.py
index 7f76df1cd..a35e47c03 100644
--- a/module/plugins/hooks/ExternalScripts.py
+++ b/module/plugins/hooks/ExternalScripts.py
@@ -1,21 +1,8 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import subprocess
+
+from itertools import chain
from os import listdir, access, X_OK, makedirs
from os.path import join, exists, basename, abspath
@@ -24,25 +11,38 @@ from module.utils import save_join
class ExternalScripts(Hook):
- __name__ = "ExternalScripts"
- __version__ = "0.23"
- __type__ = "hook"
+ __name__ = "ExternalScripts"
+ __type__ = "hook"
+ __version__ = "0.25"
__config__ = [("activated", "bool", "Activated", True)]
__description__ = """Run external scripts"""
- __author_name__ = ("mkaay", "RaNaN", "spoob")
- __author_mail__ = ("mkaay@mkaay.de", "ranan@pyload.org", "spoob@pyload.org")
+ __license__ = "GPLv3"
+ __authors__ = [("mkaay", "mkaay@mkaay.de"),
+ ("RaNaN", "ranan@pyload.org"),
+ ("spoob", "spoob@pyload.org"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ event_list = ["archive_extracted", "package_extracted", "all_archives_extracted", "all_archives_processed",
+ "allDownloadsFinished", "allDownloadsProcessed"]
+
- event_list = ["unrarFinished", "allDownloadsFinished", "allDownloadsProcessed"]
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def setup(self):
self.scripts = {}
- folders = ["download_preparing", "download_finished", "package_finished",
- "before_reconnect", "after_reconnect", "unrar_finished",
- "all_dls_finished", "all_dls_processed"]
+ folders = ["download_preparing", "download_finished", "all_downloads_finished", "all_downloads_processed",
+ "before_reconnect", "after_reconnect",
+ "package_finished", "package_extracted",
+ "archive_extracted", "all_archives_extracted", "all_archives_processed",
+ # deprecated folders
+ "unrar_finished", "all_dls_finished", "all_dls_processed"]
for folder in folders:
self.scripts[folder] = []
@@ -52,7 +52,8 @@ class ExternalScripts(Hook):
for script_type, names in self.scripts.iteritems():
if names:
- self.logInfo((_("Installed scripts for %s: ") % script_type) + ", ".join([basename(x) for x in names]))
+ self.logInfo(_("Installed scripts for"), script_type, ", ".join([basename(x) for x in names]))
+
def initPluginType(self, folder, path):
if not exists(path):
@@ -71,48 +72,75 @@ class ExternalScripts(Hook):
self.scripts[folder].append(join(path, f))
+
def callScript(self, script, *args):
try:
cmd = [script] + [str(x) if not isinstance(x, basestring) else x for x in args]
- self.logDebug("Executing %(script)s: %(cmd)s" % {"script": abspath(script), "cmd": " ".join(cmd)})
+ self.logDebug("Executing", abspath(script), " ".join(cmd))
#output goes to pyload
subprocess.Popen(cmd, bufsize=-1)
except Exception, e:
- self.logError(_("Error in %(script)s: %(error)s") % {"script": basename(script), "error": str(e)})
+ self.logError(_("Error in %(script)s: %(error)s") % {"script": basename(script), "error": e})
+
def downloadPreparing(self, pyfile):
for script in self.scripts['download_preparing']:
self.callScript(script, pyfile.pluginname, pyfile.url, pyfile.id)
+
def downloadFinished(self, pyfile):
+ download_folder = self.config['general']['download_folder']
for script in self.scripts['download_finished']:
- self.callScript(script, pyfile.pluginname, pyfile.url, pyfile.name,
- save_join(self.config['general']['download_folder'],
- pyfile.package().folder, pyfile.name), pyfile.id)
+ filename = save_join(download_folder, pyfile.package().folder, pyfile.name)
+ self.callScript(script, pyfile.pluginname, pyfile.url, pyfile.name, filename, pyfile.id)
+
def packageFinished(self, pypack):
+ download_folder = self.config['general']['download_folder']
for script in self.scripts['package_finished']:
- folder = self.config['general']['download_folder']
- folder = save_join(folder, pypack.folder)
-
+ folder = save_join(download_folder, pypack.folder)
self.callScript(script, pypack.name, folder, pypack.password, pypack.id)
+
def beforeReconnecting(self, ip):
for script in self.scripts['before_reconnect']:
self.callScript(script, ip)
+
def afterReconnecting(self, ip):
for script in self.scripts['after_reconnect']:
self.callScript(script, ip)
- def unrarFinished(self, folder, fname):
- for script in self.scripts['unrar_finished']:
- self.callScript(script, folder, fname)
+
+ def archive_extracted(self, pyfile, folder, filename, files):
+ for script in self.scripts['archive_extracted']:
+ self.callScript(script, folder, filename, files)
+ for script in self.scripts['unrar_finished']: #: deprecated
+ self.callScript(script, folder, filename)
+
+
+ def package_extracted(self, pypack):
+ download_folder = self.config['general']['download_folder']
+ for script in self.scripts['package_extracted']:
+ folder = save_join(download_folder, pypack.folder)
+ self.callScript(script, pypack.name, folder, pypack.password, pypack.id)
+
+
+ def all_archives_extracted(self):
+ for script in self.scripts['all_archives_extracted']:
+ self.callScript(script)
+
+
+ def all_archives_processed(self):
+ for script in self.scripts['all_archives_processed']:
+ self.callScript(script)
+
def allDownloadsFinished(self):
- for script in self.scripts['all_dls_finished']:
+ for script in chain(self.scripts['all_downloads_finished'], self.scripts['all_dls_finished']):
self.callScript(script)
+
def allDownloadsProcessed(self):
- for script in self.scripts['all_dls_processed']:
+ for script in chain(self.scripts['all_downloads_processed'], self.scripts['all_dls_processed']):
self.callScript(script)
diff --git a/module/plugins/hooks/ExtractArchive.py b/module/plugins/hooks/ExtractArchive.py
index c307deb8f..af78ffc93 100644
--- a/module/plugins/hooks/ExtractArchive.py
+++ b/module/plugins/hooks/ExtractArchive.py
@@ -1,19 +1,20 @@
# -*- coding: utf-8 -*-
-import sys
+from __future__ import with_statement
+
import os
+import sys
+
+from copy import copy
from os import remove, chmod, makedirs
-from os.path import exists, basename, isfile, isdir, join
+from os.path import exists, basename, isfile, isdir
from traceback import print_exc
-from copy import copy
# monkey patch bug in python 2.6 and lower
-# see http://bugs.python.org/issue6122
-# http://bugs.python.org/issue1236
-# http://bugs.python.org/issue1731717
+# 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":
- from subprocess import Popen
import errno
+ from subprocess import Popen
def _eintr_retry_call(func, *args):
while True:
@@ -24,6 +25,7 @@ if sys.version_info < (2, 7) and os.name != "nt":
continue
raise
+
# unsued timeout option for older python version
def wait(self, timeout=0):
"""Wait for child process to terminate. Returns returncode
@@ -44,48 +46,54 @@ if sys.version_info < (2, 7) and os.name != "nt":
Popen.wait = wait
if os.name != "nt":
+ from grp import getgrnam
from os import chown
from pwd import getpwnam
- from grp import getgrnam
-from module.utils import save_join, fs_encode
from module.plugins.Hook import Hook, threaded, Expose
-from module.plugins.internal.AbstractExtractor import ArchiveError, CRCError, WrongPassword
+from module.plugins.internal.Extractor import ArchiveError, CRCError, PasswordError
+from module.utils import save_join, uniqify
class ExtractArchive(Hook):
- """
- Provides: unrarFinished (folder, filename)
- """
- __name__ = "ExtractArchive"
- __version__ = "0.16"
- __type__ = "hook"
-
- __config__ = [("activated", "bool", "Activated", True),
- ("fullpath", "bool", "Extract full path", True),
- ("overwrite", "bool", "Overwrite files", True),
- ("passwordfile", "file", "password file", "unrar_passwords.txt"),
- ("deletearchive", "bool", "Delete archives when done", False),
- ("subfolder", "bool", "Create subfolder for each package", False),
- ("destination", "folder", "Extract files to", ""),
- ("excludefiles", "str", "Exclude files from unpacking (seperated by ;)", ""),
- ("recursive", "bool", "Extract archives in archvies", True),
- ("queue", "bool", "Wait for all downloads to be finished", True),
- ("renice", "int", "CPU Priority", 0)]
+ __name__ = "ExtractArchive"
+ __type__ = "hook"
+ __version__ = "1.02"
+
+ __config__ = [("activated" , "bool" , "Activated" , True ),
+ ("fullpath" , "bool" , "Extract full path" , True ),
+ ("overwrite" , "bool" , "Overwrite files" , False ),
+ ("keepbroken" , "bool" , "Extract broken archives" , False ),
+ ("repair" , "bool" , "Repair broken archives" , True ),
+ ("passwordfile" , "file" , "Store passwords in 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" , "" ),
+ ("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 ),
+ ("queue" , "bool" , "Wait for all downloads to be finished" , True ),
+ ("renice" , "int" , "CPU Priority" , 0 )]
__description__ = """Extract different kind of archives"""
- __author_name__ = ("pyLoad Team", "AndroKev")
- __author_mail__ = ("admin@pyload.org", "@pyloadforum")
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
event_list = ["allDownloadsProcessed"]
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
+
+
def setup(self):
- self.plugins = []
+ self.plugins = []
self.passwords = []
names = []
- for p in ("UnRar", "UnZip"):
+ for p in ("UnRar", "SevenZip", "UnZip"):
try:
module = self.core.pluginManager.loadModule("internal", p)
klass = getattr(module, p)
@@ -97,12 +105,12 @@ class ExtractArchive(Hook):
if e.errno == 2:
self.logInfo(_("No %s installed") % p)
else:
- self.logWarning(_("Could not activate %s") % p, str(e))
+ self.logWarning(_("Could not activate %s") % p, e)
if self.core.debug:
print_exc()
except Exception, e:
- self.logWarning(_("Could not activate %s") % p, str(e))
+ self.logWarning(_("Could not activate %s") % p, e)
if self.core.debug:
print_exc()
@@ -114,138 +122,230 @@ class ExtractArchive(Hook):
# queue with package ids
self.queue = []
+
@Expose
def extractPackage(self, id):
""" Extract package with given id"""
self.manager.startThread(self.extract, [id])
+
def packageFinished(self, pypack):
+ pid = pypack.id
if self.getConfig("queue"):
self.logInfo(_("Package %s queued for later extracting") % pypack.name)
- self.queue.append(pypack.id)
+ self.queue.append(pid)
else:
- self.manager.startThread(self.extract, [pypack.id])
+ self.extractPackage(pid)
+
@threaded
def allDownloadsProcessed(self, thread):
local = copy(self.queue)
+
del self.queue[:]
- self.extract(local, thread)
+
+ if self.extract(local, thread): #: 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):
+ processed = []
+ extracted = []
+ failed = []
+
+ clearlist = lambda string: [x.lstrip('.') for x in string.replace(' ', '').replace(',', '|').replace(';', '|').split('|')]
+
+ destination = self.getConfig("destination")
+ subfolder = self.getConfig("subfolder")
+ fullpath = self.getConfig("fullpath")
+ overwrite = self.getConfig("overwrite")
+ extensions = clearlist(self.getConfig("extensions"))
+ excludefiles = clearlist(self.getConfig("excludefiles"))
+ renice = self.getConfig("renice")
+ recursive = self.getConfig("recursive")
+ delete = self.getConfig("delete")
+ keepbroken = self.getConfig("keepbroken")
+
+ if extensions:
+ self.logDebug("Extensions allowed: %s" % "|.".join(extensions))
+
# reload from txt file
self.reloadPasswords()
# dl folder
dl = self.config['general']['download_folder']
- extracted = []
-
#iterate packages -> plugins -> targets
for pid in ids:
p = self.core.files.getPackage(pid)
- self.logInfo(_("Check package %s") % p.name)
+ self.logInfo(_("Check package: %s") % p.name)
if not p:
continue
# determine output folder
- out = save_join(dl, p.folder, "")
- # force trailing slash
-
- if self.getConfig("destination") and self.getConfig("destination").lower() != "none":
-
- out = save_join(dl, p.folder, self.getConfig("destination"), "")
- #relative to package folder if destination is relative, otherwise absolute path overwrites them
+ out = save_join(dl, p.folder, destination, "") #: force trailing slash
- if self.getConfig("subfolder"):
- out = join(out, fs_encode(p.folder))
+ if subfolder:
+ out = save_join(out, p.folder)
- if not exists(out):
- makedirs(out)
+ if not exists(out):
+ makedirs(out)
files_ids = [(save_join(dl, p.folder, x['name']), x['id']) for x in p.getChildren().itervalues()]
- matched = False
+ matched = False
+ success = True
# check as long there are unseen files
while files_ids:
new_files_ids = []
+ if extensions:
+ files_ids = [(file, id) for file, id in files_ids if filter(lambda ext: file.endswith(ext), extensions)]
+
for plugin in self.plugins:
targets = plugin.getTargets(files_ids)
+
if targets:
self.logDebug("Targets for %s: %s" % (plugin.__name__, targets))
matched = True
+
for target, fid in targets:
- if target in extracted:
+ if target in processed:
self.logDebug(basename(target), "skipped")
continue
- extracted.append(target) # prevent extracting same file twice
- klass = plugin(self, target, out, self.getConfig("fullpath"), self.getConfig("overwrite"), self.getConfig("excludefiles"),
- self.getConfig("renice"))
- klass.init()
+ processed.append(target) # prevent extracting same file twice
+
+ self.logInfo(basename(target), _("Extract to: %s") % out)
+ try:
+ klass = plugin(self,
+ target,
+ out,
+ p.password,
+ fullpath,
+ overwrite,
+ excludefiles,
+ renice,
+ delete,
+ keepbroken)
+ klass.init()
+
+ new_files = self._extract(klass, fid, thread)
+
+ except Exception, e:
+ self.logError(basename(target), e)
+ new_files = None
+
+ if new_files is None:
+ self.logWarning(basename(target), _("No files extracted"))
+ success = False
+ continue
- self.logInfo(basename(target), _("Extract to %s") % out)
- new_files = self.startExtracting(klass, fid, p.password.strip().splitlines(), thread)
- self.logDebug("Extracted: %s" % new_files)
+ self.logDebug("Extracted files: %s" % new_files)
self.setPermissions(new_files)
for file in new_files:
if not exists(file):
- self.logDebug("new file %s does not exists" % file)
+ self.logDebug("New file %s does not exists" % file)
continue
- if self.getConfig("recursive") and isfile(file):
+ if recursive and isfile(file):
new_files_ids.append((file, fid)) # append as new target
files_ids = new_files_ids # also check extracted files
- if not matched:
+ if matched:
+ if success:
+ extracted.append(pid)
+ self.manager.dispatchEvent("package_extracted", p)
+ else:
+ failed.append(pid)
+ self.manager.dispatchEvent("package_extract_failed", p)
+ else:
self.logInfo(_("No files found to extract"))
- def startExtracting(self, plugin, fid, passwords, thread):
+ if not matched or not success and subfolder:
+ try:
+ os.rmdir(out)
+ except OSError:
+ pass
+
+ return True if not failed else False
+
+
+ def _extract(self, plugin, fid, thread):
pyfile = self.core.files.getFile(fid)
- if not pyfile:
- return []
pyfile.setCustomStatus(_("extracting"))
thread.addActive(pyfile) # keep this file until everything is done
try:
- progress = lambda x: pyfile.setProgress(x)
- success = False
+ progress = lambda x: pyfile.setProgress(x)
+ encrypted = False
+ passwords = self.getPasswords()
- if not plugin.checkArchive():
+ try:
+ self.logInfo(basename(plugin.file), "Verifying...")
+
+ tmp_password = plugin.password
+ plugin.password = "" #: Force verifying without password
+
+ plugin.verify()
+
+ except PasswordError:
+ encrypted = True
+
+ except CRCError:
+ self.logWarning(basename(plugin.file), _("Archive damaged"))
+
+ if not self.getConfig("repair"):
+ raise CRCError
+
+ elif plugin.repair():
+ self.logInfo(basename(plugin.file), _("Successfully repaired"))
+
+ elif not self.getConfig("keepbroken"):
+ raise ArchiveError(_("Broken archive"))
+
+ else:
+ self.logInfo(basename(plugin.file), _("All OK"))
+
+ plugin.password = tmp_password
+
+ if not encrypted:
plugin.extract(progress)
- success = True
+
else:
self.logInfo(basename(plugin.file), _("Password protected"))
- self.logDebug("Passwords: %s" % str(passwords))
- pwlist = copy(self.getPasswords())
- #remove already supplied pws from list (only local)
- for pw in passwords:
- if pw in pwlist:
- pwlist.remove(pw)
+ if plugin.password:
+ passwords.insert(0, plugin.password)
+ passwords = uniqify(self.passwords)
+ self.logDebug("Password: %s" % plugin.password)
+ else:
+ self.logDebug("No package password provided")
- for pw in passwords + pwlist:
+ for pw in passwords:
try:
self.logDebug("Try password: %s" % pw)
- if plugin.checkPassword(pw):
- plugin.extract(progress, pw)
+
+ if plugin.setPassword(pw):
+ plugin.extract(progress)
self.addPassword(pw)
- success = True
break
- except WrongPassword:
- self.logDebug("Password was wrong")
+ else:
+ raise PasswordError
- if not success:
- self.logError(basename(plugin.file), _("Wrong password"))
- return []
+ except PasswordError:
+ self.logDebug("Password was wrong")
+ else:
+ raise PasswordError
if self.core.debug:
self.logDebug("Would delete: %s" % ", ".join(plugin.getDeleteFiles()))
- if self.getConfig("deletearchive"):
+ if self.getConfig("delete"):
files = plugin.getDeleteFiles()
self.logInfo(_("Deleting %s files") % len(files))
for f in files:
@@ -255,57 +355,76 @@ class ExtractArchive(Hook):
self.logDebug("%s does not exists" % f)
self.logInfo(basename(plugin.file), _("Extracting finished"))
- self.manager.dispatchEvent("unrarFinished", plugin.out, plugin.file)
- return plugin.getExtractedFiles()
+ extracted_files = plugin.getExtractedFiles()
+ self.manager.dispatchEvent("archive_extracted", pyfile, plugin.out, plugin.file, extracted_files)
+
+ return extracted_files
+
+ except PasswordError:
+ self.logError(basename(plugin.file), _("Wrong password" if passwords else "No password found"))
+ plugin.password = ""
- except ArchiveError, e:
- self.logError(basename(plugin.file), _("Archive Error"), str(e))
except CRCError:
self.logError(basename(plugin.file), _("CRC Mismatch"))
+
+ except ArchiveError, e:
+ self.logError(basename(plugin.file), _("Archive Error"), e)
+
except Exception, e:
if self.core.debug:
print_exc()
- self.logError(basename(plugin.file), _("Unknown Error"), str(e))
+ self.logError(basename(plugin.file), _("Unknown Error"), e)
+
+ self.manager.dispatchEvent("archive_extract_failed", pyfile)
+
+ self.logError(basename(plugin.file), _("Extract failed"))
- return []
@Expose
def getPasswords(self):
""" List of saved passwords """
return self.passwords
+
def reloadPasswords(self):
- pwfile = self.getConfig("passwordfile")
- if not exists(pwfile):
- open(pwfile, "wb").close()
+ passwordfile = self.getConfig("passwordfile")
- passwords = []
- f = open(pwfile, "rb")
- for pw in f.read().splitlines():
- passwords.append(pw)
- f.close()
+ try:
+ passwords = []
+ with open(passwordfile, "a+") as f:
+ for pw in f.read().splitlines():
+ passwords.append(pw)
+
+ except IOError, e:
+ self.logError(e)
+
+ else:
+ self.passwords = passwords
- self.passwords = passwords
@Expose
def addPassword(self, pw):
""" Adds a password to saved list"""
- pwfile = self.getConfig("passwordfile")
+ passwordfile = self.getConfig("passwordfile")
- if pw in self.passwords:
- self.passwords.remove(pw)
self.passwords.insert(0, pw)
+ self.passwords = uniqify(self.passwords)
+
+ try:
+ with open(passwordfile, "wb") as f:
+ for pw in self.passwords:
+ f.write(pw + '\n')
+
+ except IOError, e:
+ self.logError(e)
- f = open(pwfile, "wb")
- for pw in self.passwords:
- f.write(pw + "\n")
- f.close()
def setPermissions(self, files):
for f in files:
if not exists(f):
continue
+
try:
if self.config['permission']['change_file']:
if isfile(f):
@@ -317,5 +436,6 @@ class ExtractArchive(Hook):
uid = getpwnam(self.config['permission']['user'])[2]
gid = getgrnam(self.config['permission']['group'])[2]
chown(f, uid, gid)
+
except Exception, e:
self.logWarning(_("Setting User and Group failed"), e)
diff --git a/module/plugins/hooks/FastixRu.py b/module/plugins/hooks/FastixRu.py
index aa020ea37..73297eb23 100644
--- a/module/plugins/hooks/FastixRu.py
+++ b/module/plugins/hooks/FastixRu.py
@@ -1,30 +1,28 @@
# -*- coding: utf-8 -*-
-# should be working
-
-from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
from module.common.json_layer import json_loads
+from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
-class FastixRu(MultiHoster):
- __name__ = "FastixRu"
- __version__ = "0.02"
- __type__ = "hook"
+class FastixRu(MultiHook):
+ __name__ = "FastixRu"
+ __type__ = "hook"
+ __version__ = "0.03"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("unloadFailing", "bool", "Revert to standard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """Fastix.ru hook plugin"""
- __author_name__ = "Massimo Rosamilia"
- __author_mail__ = "max@spiritix.eu"
+ __license__ = "GPLv3"
+ __authors__ = [("Massimo Rosamilia", "max@spiritix.eu")]
def getHoster(self):
- page = getURL(
- "http://fastix.ru/api_v2/?apikey=5182964c3f8f9a7f0b00000a_kelmFB4n1IrnCDYuIFn2y&sub=allowed_sources")
+ page = getURL("http://fastix.ru/api_v2",
+ get={'apikey': "5182964c3f8f9a7f0b00000a_kelmFB4n1IrnCDYuIFn2y",
+ 'sub' : "allowed_sources"})
host_list = json_loads(page)
host_list = host_list['allow']
return host_list
diff --git a/module/plugins/hooks/FreeWayMe.py b/module/plugins/hooks/FreeWayMe.py
index 3d2f7fcef..0b71fc35b 100644
--- a/module/plugins/hooks/FreeWayMe.py
+++ b/module/plugins/hooks/FreeWayMe.py
@@ -1,41 +1,25 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class FreeWayMe(MultiHoster):
- __name__ = "FreeWayMe"
- __version__ = "0.11"
- __type__ = "hook"
+class FreeWayMe(MultiHook):
+ __name__ = "FreeWayMe"
+ __type__ = "hook"
+ __version__ = "0.12"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to stanard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """FreeWay.me hook plugin"""
- __author_name__ = "Nicolas Giese"
- __author_mail__ = "james@free-way.me"
+ __license__ = "GPLv3"
+ __authors__ = [("Nicolas Giese", "james@free-way.me")]
def getHoster(self):
- hostis = getURL("https://www.free-way.me/ajax/jd.php", get={"id": 3}).replace("\"", "").strip()
- self.logDebug("hosters: %s" % hostis)
+ hostis = 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/HotFolder.py b/module/plugins/hooks/HotFolder.py
index 08ef93812..b0b59e2ba 100644
--- a/module/plugins/hooks/HotFolder.py
+++ b/module/plugins/hooks/HotFolder.py
@@ -1,82 +1,66 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-from os import makedirs
-from os import listdir
-from os.path import exists
-from os.path import join
-from os.path import isfile
-from shutil import move
+from __future__ import with_statement
+
import time
+from os import listdir, makedirs
+from os.path import exists, isfile, join
+from shutil import move
+
from module.plugins.Hook import Hook
+from module.utils import fs_encode, save_join
class HotFolder(Hook):
- __name__ = "HotFolder"
- __version__ = "0.11"
- __type__ = "hook"
+ __name__ = "HotFolder"
+ __type__ = "hook"
+ __version__ = "0.12"
- __config__ = [("activated", "bool", "Activated", False),
- ("folder", "str", "Folder to observe", "container"),
+ __config__ = [("folder", "str", "Folder to observe", "container"),
("watch_file", "bool", "Observe link file", False),
("keep", "bool", "Keep added containers", True),
("file", "str", "Link file", "links.txt")]
__description__ = """Observe folder and file for changes and add container and links"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.de"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.de")]
def setup(self):
self.interval = 10
+
def periodical(self):
- if not exists(join(self.getConfig("folder"), "finished")):
- makedirs(join(self.getConfig("folder"), "finished"))
+ folder = fs_encode(self.getConfig("folder"))
+
+ try:
+ if not exists(join(folder, "finished")):
+ makedirs(join(folder, "finished"))
- if self.getConfig("watch_file"):
+ if self.getConfig("watch_file"):
+ with open(fs_encode(self.getConfig("file")), "a+") as f:
+ content = f.read().strip()
- if not exists(self.getConfig("file")):
- f = open(self.getConfig("file"), "wb")
- f.close()
+ if content:
+ name = "%s_%s.txt" % (self.getConfig("file"), time.strftime("%H-%M-%S_%d%b%Y"))
- f = open(self.getConfig("file"), "rb")
- content = f.read().strip()
- f.close()
- f = open(self.getConfig("file"), "wb")
- f.close()
- if content:
- name = "%s_%s.txt" % (self.getConfig("file"), time.strftime("%H-%M-%S_%d%b%Y"))
+ with open(save_join(folder, "finished", name), "wb") as f:
+ f.write(content)
- f = open(join(self.getConfig("folder"), "finished", name), "wb")
- f.write(content)
- f.close()
+ self.core.api.addPackage(f.name, [f.name], 1)
- self.core.api.addPackage(f.name, [f.name], 1)
+ for f in listdir(folder):
+ path = join(folder, f)
- for f in listdir(self.getConfig("folder")):
- path = join(self.getConfig("folder"), f)
+ if not isfile(path) or f.endswith("~") or f.startswith("#") or f.startswith("."):
+ continue
- if not isfile(path) or f.endswith("~") or f.startswith("#") or f.startswith("."):
- continue
+ newpath = join(folder, "finished", f if self.getConfig("keep") else "tmp_" + f)
+ move(path, newpath)
- newpath = join(self.getConfig("folder"), "finished", f if self.getConfig("keep") else "tmp_" + f)
- move(path, newpath)
+ self.logInfo(_("Added %s from HotFolder") % f)
+ self.core.api.addPackage(f, [newpath], 1)
- self.logInfo(_("Added %s from HotFolder") % f)
- self.core.api.addPackage(f, [newpath], 1)
+ except IOError, e:
+ self.logError(e)
diff --git a/module/plugins/hooks/IRCInterface.py b/module/plugins/hooks/IRCInterface.py
index a29874469..efd4e411d 100644
--- a/module/plugins/hooks/IRCInterface.py
+++ b/module/plugins/hooks/IRCInterface.py
@@ -1,45 +1,32 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+import re
+import socket
+import ssl
+import time
+from pycurl import FORM_FILE
from select import select
-import socket
from threading import Thread
-import time
from time import sleep
from traceback import print_exc
-import re
-from pycurl import FORM_FILE
-from module.plugins.Hook import Hook
+from module.Api import PackageDoesNotExists, FileDoesNotExists
from module.network.RequestFactory import getURL
+from module.plugins.Hook import Hook
from module.utils import formatSize
-from module.Api import PackageDoesNotExists, FileDoesNotExists
class IRCInterface(Thread, Hook):
- __name__ = "IRCInterface"
- __version__ = "0.11"
- __type__ = "hook"
+ __name__ = "IRCInterface"
+ __type__ = "hook"
+ __version__ = "0.13"
- __config__ = [("activated", "bool", "Activated", False),
- ("host", "str", "IRC-Server Address", "Enter your server here!"),
+ __config__ = [("host", "str", "IRC-Server Address", "Enter your server here!"),
("port", "int", "IRC-Server Port", 6667),
("ident", "str", "Clients ident", "pyload-irc"),
("realname", "str", "Realname", "pyload-irc"),
+ ("ssl", "bool", "Use SSL", False),
("nick", "str", "Nickname the Client will take", "pyLoad-IRC"),
("owner", "str", "Nickname the Client will accept commands from", "Enter your nick here!"),
("info_file", "bool", "Inform about every file finished", False),
@@ -47,16 +34,20 @@ class IRCInterface(Thread, Hook):
("captcha", "bool", "Send captcha requests", True)]
__description__ = """Connect to irc and let owner perform different tasks"""
- __author_name__ = "Jeix"
- __author_mail__ = "Jeix@hasnomail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Jeix", "Jeix@hasnomail.com")]
def __init__(self, core, manager):
Thread.__init__(self)
Hook.__init__(self, core, manager)
self.setDaemon(True)
- # self.sm = core.server_methods
- self.api = core.api # todo, only use api
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
+
def coreReady(self):
self.abort = False
@@ -65,6 +56,7 @@ class IRCInterface(Thread, Hook):
self.start()
+
def packageFinished(self, pypack):
try:
if self.getConfig("info_pack"):
@@ -72,6 +64,7 @@ class IRCInterface(Thread, Hook):
except:
pass
+
def downloadFinished(self, pyfile):
try:
if self.getConfig("info_file"):
@@ -80,6 +73,7 @@ class IRCInterface(Thread, Hook):
except:
pass
+
def newCaptchaTask(self, task):
if self.getConfig("captcha") and task.isTextual():
task.handler.append(self)
@@ -92,19 +86,24 @@ class IRCInterface(Thread, Hook):
self.response(_("New Captcha Request: %s") % url)
self.response(_("Answer with 'c %s text on the captcha'") % task.id)
+
def run(self):
# connect to IRC etc.
self.sock = socket.socket()
host = self.getConfig("host")
self.sock.connect((host, self.getConfig("port")))
+
+ if self.getConfig("ssl"):
+ self.sock = ssl.wrap_socket(self.sock, cert_reqs=ssl.CERT_NONE) #@TODO: support certificate
+
nick = self.getConfig("nick")
self.sock.send("NICK %s\r\n" % nick)
self.sock.send("USER %s %s bla :%s\r\n" % (nick, host, nick))
for t in self.getConfig("owner").split():
if t.strip().startswith("#"):
self.sock.send("JOIN %s\r\n" % t.strip())
- self.logInfo("pyLoad IRC: Connected to %s!" % host)
- self.logInfo("pyLoad IRC: Switching to listening mode!")
+ self.logInfo(_("Connected to"), host)
+ self.logInfo(_("Switching to listening mode!"))
try:
self.main_loop()
@@ -113,6 +112,7 @@ class IRCInterface(Thread, Hook):
print_exc()
self.sock.close()
+
def main_loop(self):
readbuffer = ""
while True:
@@ -151,6 +151,7 @@ class IRCInterface(Thread, Hook):
self.handle_events(msg)
+
def handle_events(self, msg):
if not msg['origin'].split("!", 1)[0] in self.getConfig("owner").split():
return
@@ -163,15 +164,15 @@ class IRCInterface(Thread, Hook):
# HANDLE CTCP ANTI FLOOD/BOT PROTECTION
if msg['text'] == "\x01VERSION\x01":
- self.logDebug("Sending CTCP VERSION.")
+ self.logDebug("Sending CTCP VERSION")
self.sock.send("NOTICE %s :%s\r\n" % (msg['origin'], "pyLoad! IRC Interface"))
return
elif msg['text'] == "\x01TIME\x01":
- self.logDebug("Sending CTCP TIME.")
+ self.logDebug("Sending CTCP TIME")
self.sock.send("NOTICE %s :%d\r\n" % (msg['origin'], time.time()))
return
elif msg['text'] == "\x01LAG\x01":
- self.logDebug("Received CTCP LAG.") # don't know how to answer
+ self.logDebug("Received CTCP LAG") #: don't know how to answer
return
trigger = "pass"
@@ -191,7 +192,8 @@ class IRCInterface(Thread, Hook):
for line in res:
self.response(line, msg['origin'])
except Exception, e:
- self.logError("pyLoad IRC: " + repr(e))
+ self.logError(e)
+
def response(self, msg, origin=""):
if origin == "":
@@ -200,13 +202,15 @@ class IRCInterface(Thread, Hook):
else:
self.sock.send("PRIVMSG %s :%s\r\n" % (origin.split("!", 1)[0], msg))
+
#### Events
def event_pass(self, args):
return []
+
def event_status(self, args):
- downloads = self.api.statusDownloads()
+ downloads = self.core.api.statusDownloads()
if not downloads:
return ["INFO: There are no active downloads currently."]
@@ -230,8 +234,9 @@ class IRCInterface(Thread, Hook):
))
return lines
+
def event_queue(self, args):
- ps = self.api.getQueueData()
+ ps = self.core.api.getQueueData()
if not ps:
return ["INFO: There are no packages in queue."]
@@ -242,8 +247,9 @@ class IRCInterface(Thread, Hook):
return lines
+
def event_collector(self, args):
- ps = self.api.getCollectorData()
+ ps = self.core.api.getCollectorData()
if not ps:
return ["INFO: No packages in collector!"]
@@ -253,19 +259,21 @@ class IRCInterface(Thread, Hook):
return lines
+
def event_info(self, args):
if not args:
return ["ERROR: Use info like this: info <id>"]
info = None
try:
- info = self.api.getFileData(int(args[0]))
+ info = self.core.api.getFileData(int(args[0]))
except FileDoesNotExists:
return ["ERROR: Link doesn't exists."]
return ['LINK #%s: %s (%s) [%s][%s]' % (info.fid, info.name, info.format_size, info.statusmsg, info.plugin)]
+
def event_packinfo(self, args):
if not args:
return ["ERROR: Use packinfo like this: packinfo <id>"]
@@ -273,7 +281,7 @@ class IRCInterface(Thread, Hook):
lines = []
pack = None
try:
- pack = self.api.getPackageData(int(args[0]))
+ pack = self.core.api.getPackageData(int(args[0]))
except PackageDoesNotExists:
return ["ERROR: Package doesn't exists."]
@@ -297,6 +305,7 @@ class IRCInterface(Thread, Hook):
return lines
+
def event_more(self, args):
if not self.more:
return ["No more information to display."]
@@ -307,14 +316,17 @@ class IRCInterface(Thread, Hook):
return lines
+
def event_start(self, args):
- self.api.unpauseServer()
+ self.core.api.unpauseServer()
return ["INFO: Starting downloads."]
+
def event_stop(self, args):
- self.api.pauseServer()
+ self.core.api.pauseServer()
return ["INFO: No new downloads will be started."]
+
def event_add(self, args):
if len(args) < 2:
return ['ERROR: Add links like this: "add <packagename|id> links". ',
@@ -327,7 +339,7 @@ class IRCInterface(Thread, Hook):
count_failed = 0
try:
id = int(pack)
- pack = self.api.getPackageData(id)
+ pack = self.core.api.getPackageData(id)
if not pack:
return ["ERROR: Package doesn't exists."]
@@ -337,48 +349,52 @@ class IRCInterface(Thread, Hook):
except:
# create new package
- id = self.api.addPackage(pack, links, 1)
+ id = self.core.api.addPackage(pack, links, 1)
return ["INFO: Created new Package %s [#%d] with %d links." % (pack, id, len(links))]
+
def event_del(self, args):
if len(args) < 2:
return ["ERROR: Use del command like this: del -p|-l <id> [...] (-p indicates that the ids are from packages, -l indicates that the ids are from links)"]
if args[0] == "-p":
- ret = self.api.deletePackages(map(int, args[1:]))
+ ret = self.core.api.deletePackages(map(int, args[1:]))
return ["INFO: Deleted %d packages!" % len(args[1:])]
elif args[0] == "-l":
- ret = self.api.delLinks(map(int, args[1:]))
+ ret = self.core.api.delLinks(map(int, args[1:]))
return ["INFO: Deleted %d links!" % len(args[1:])]
else:
return ["ERROR: Use del command like this: del <-p|-l> <id> [...] (-p indicates that the ids are from packages, -l indicates that the ids are from links)"]
+
def event_push(self, args):
if not args:
return ["ERROR: Push package to queue like this: push <package id>"]
id = int(args[0])
try:
- info = self.api.getPackageInfo(id)
+ info = self.core.api.getPackageInfo(id)
except PackageDoesNotExists:
return ["ERROR: Package #%d does not exist." % id]
- self.api.pushToQueue(id)
+ self.core.api.pushToQueue(id)
return ["INFO: Pushed package #%d to queue." % id]
+
def event_pull(self, args):
if not args:
return ["ERROR: Pull package from queue like this: pull <package id>."]
id = int(args[0])
- if not self.api.getPackageData(id):
+ if not self.core.api.getPackageData(id):
return ["ERROR: Package #%d does not exist." % id]
- self.api.pullFromQueue(id)
+ self.core.api.pullFromQueue(id)
return ["INFO: Pulled package #%d from queue to collector." % id]
+
def event_c(self, args):
""" captcha answer """
if not args:
@@ -391,6 +407,7 @@ class IRCInterface(Thread, Hook):
task.setResult(" ".join(args[1:]))
return ["INFO: Result %s saved." % " ".join(args[1:])]
+
def event_help(self, args):
lines = ["The following commands are available:",
"add <package|packid> <links> [...] Adds link to package. (creates new package if it does not exist)",
@@ -414,5 +431,6 @@ class IRCError(Exception):
def __init__(self, value):
self.value = value
+
def __str__(self):
return repr(self.value)
diff --git a/module/plugins/hooks/ImageTyperz.py b/module/plugins/hooks/ImageTyperz.py
index 4d7be96e3..f89d64c37 100644
--- a/module/plugins/hooks/ImageTyperz.py
+++ b/module/plugins/hooks/ImageTyperz.py
@@ -1,24 +1,12 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
from __future__ import with_statement
-from thread import start_new_thread
-from pycurl import FORM_FILE, LOW_SPEED_TIME
+
import re
+
from base64 import b64encode
+from pycurl import FORM_FILE, LOW_SPEED_TIME
+from thread import start_new_thread
from module.network.RequestFactory import getURL, getRequest
from module.plugins.Hook import Hook
@@ -29,61 +17,74 @@ 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"
- __version__ = "0.04"
- __type__ = "hook"
+ __name__ = "ImageTyperz"
+ __type__ = "hook"
+ __version__ = "0.05"
- __config__ = [("activated", "bool", "Activated", False),
- ("username", "str", "Username", ""),
+ __config__ = [("username", "str", "Username", ""),
("passkey", "password", "Password", ""),
("force", "bool", "Force IT even if client is connected", False)]
__description__ = """Send captchas to ImageTyperz.com"""
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+ __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"
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
+
+
def setup(self):
- self.info = {}
+ self.info = {} #@TODO: Remove in 0.4.10
+
def getCredits(self):
- response = getURL(self.GETCREDITS_URL, post={"action": "REQUESTBALANCE", "username": self.getConfig("username"),
- "password": self.getConfig("passkey")})
+ res = getURL(self.GETCREDITS_URL,
+ post={'action': "REQUESTBALANCE",
+ 'username': self.getConfig("username"),
+ 'password': self.getConfig("passkey")})
- if response.startswith('ERROR'):
- raise ImageTyperzException(response)
+ if res.startswith('ERROR'):
+ raise ImageTyperzException(res)
try:
- balance = float(response)
+ balance = float(res)
except:
- raise ImageTyperzException("invalid response")
+ raise ImageTyperzException("Invalid response")
- self.logInfo("Account balance: $%s left" % 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:
- #workaround multipart-post bug in HTTPRequest.py
- if re.match("^[A-Za-z0-9]*$", self.getConfig("passkey")):
+ #workaround multipart-post bug in HTTPRequest.py
+ if re.match("^\w*$", self.getConfig("passkey")):
multipart = True
data = (FORM_FILE, captcha)
else:
@@ -92,24 +93,26 @@ class ImageTyperz(Hook):
data = f.read()
data = b64encode(data)
- response = req.load(self.SUBMIT_URL, post={"action": "UPLOADCAPTCHA",
- "username": self.getConfig("username"),
- "password": self.getConfig("passkey"), "file": data},
- multipart=multipart)
+ 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 response.startswith("ERROR"):
- raise ImageTyperzException(response)
+ if res.startswith("ERROR"):
+ raise ImageTyperzException(res)
else:
- data = response.split('|')
+ data = res.split('|')
if len(data) == 2:
ticket, result = data
else:
- raise ImageTyperzException("Unknown response %s" % response)
+ raise ImageTyperzException("Unknown response: %s" % res)
return ticket, result
+
def newCaptchaTask(self, task):
if "service" in task.data:
return False
@@ -130,18 +133,22 @@ class ImageTyperz(Hook):
start_new_thread(self.processCaptcha, (task,))
else:
- self.logInfo("Your %s account has not enough credits" % self.__name__)
+ 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:
- response = getURL(self.RESPOND_URL, post={"action": "SETBADIMAGE", "username": self.getConfig("username"),
- "password": self.getConfig("passkey"),
- "imageid": task.data['ticket']})
-
- if response == "SUCCESS":
- self.logInfo("Bad captcha solution received, requested refund")
+ 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", response)
+ self.logError(_("Bad captcha solution received, refund request failed"), res)
+
def processCaptcha(self, task):
c = task.captchaFile
diff --git a/module/plugins/hooks/LinkdecrypterCom.py b/module/plugins/hooks/LinkdecrypterCom.py
index 4e08372fe..b0ce335d0 100644
--- a/module/plugins/hooks/LinkdecrypterCom.py
+++ b/module/plugins/hooks/LinkdecrypterCom.py
@@ -1,37 +1,25 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from module.plugins.Hook import Hook
from module.network.RequestFactory import getURL
+from module.plugins.Hook import Hook
from module.utils import remove_chars
class LinkdecrypterCom(Hook):
- __name__ = "LinkdecrypterCom"
- __version__ = "0.19"
- __type__ = "hook"
-
- __config__ = [("activated", "bool", "Activated", False)]
+ __name__ = "LinkdecrypterCom"
+ __type__ = "hook"
+ __version__ = "0.21"
__description__ = """Linkdecrypter.com hook plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def coreReady(self):
@@ -40,9 +28,16 @@ class LinkdecrypterCom(Hook):
except Exception, e:
self.logError(e)
+
def loadPatterns(self):
- page = getURL("http://linkdecrypter.com/")
- m = re.search(r'<b>Supported\(\d+\)</b>: <i>([^+<]*)', page)
+ html = getURL("http://linkdecrypter.com/")
+
+ m = re.search(r'<title>', html)
+ if m is None:
+ self.logError(_("Linkdecrypter site is down"))
+ return
+
+ m = re.search(r'<b>Supported\(\d+\)</b>: <i>([^+<]*)', html)
if m is None:
self.logError(_("Crypter list not found"))
return
@@ -61,10 +56,10 @@ class LinkdecrypterCom(Hook):
self.logError(_("Crypter list is empty"))
return
- regexp = r"https?://([^.]+\.)*?(%s)/.*" % "|".join(online)
+ regexp = r'https?://([^.]+\.)*?(%s)/.*' % '|'.join(online)
dict = self.core.pluginManager.crypterPlugins[self.__name__]
dict['pattern'] = regexp
dict['re'] = re.compile(regexp)
- self.logDebug("REGEXP: " + regexp)
+ self.logDebug("Loaded pattern: %s" % regexp)
diff --git a/module/plugins/hooks/LinksnappyCom.py b/module/plugins/hooks/LinksnappyCom.py
index a0e5b8d38..96bf1c0d1 100644
--- a/module/plugins/hooks/LinksnappyCom.py
+++ b/module/plugins/hooks/LinksnappyCom.py
@@ -1,28 +1,27 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.MultiHoster import MultiHoster
-from module.network.RequestFactory import getURL
from module.common.json_layer import json_loads
+from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
-class LinksnappyCom(MultiHoster):
- __name__ = "LinksnappyCom"
- __version__ = "0.01"
- __type__ = "hook"
+class LinksnappyCom(MultiHook):
+ __name__ = "LinksnappyCom"
+ __type__ = "hook"
+ __version__ = "0.02"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to standard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """Linksnappy.com hook plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
def getHoster(self):
- json_data = getURL('http://gen.linksnappy.com/lseAPI.php?act=FILEHOSTS')
+ json_data = 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
index 22945cc0f..f3a0c31ea 100644
--- a/module/plugins/hooks/MegaDebridEu.py
+++ b/module/plugins/hooks/MegaDebridEu.py
@@ -1,45 +1,30 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.MultiHoster import MultiHoster
-from module.network.RequestFactory import getURL
+
from module.common.json_layer import json_loads
+from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
-class MegaDebridEu(MultiHoster):
- __name__ = "MegaDebridEu"
- __version__ = "0.02"
- __type__ = "hook"
+class MegaDebridEu(MultiHook):
+ __name__ = "MegaDebridEu"
+ __type__ = "hook"
+ __version__ = "0.03"
- __config__ = [("activated", "bool", "Activated", False),
- ("unloadFailing", "bool", "Revert to standard download if download fails", False)]
+ __config__ = [("unloadFailing", "bool", "Revert to standard download if download fails", False)]
__description__ = """mega-debrid.eu hook plugin"""
- __author_name__ = "D.Ducatel"
- __author_mail__ = "dducatel@je-geek.fr"
+ __license__ = "GPLv3"
+ __authors__ = [("D.Ducatel", "dducatel@je-geek.fr")]
def getHoster(self):
- reponse = getURL('http://www.mega-debrid.eu/api.php?action=getHosters')
+ reponse = 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")
+ self.logError(_("Unable to retrieve hoster list"))
host_list = list()
return host_list
diff --git a/module/plugins/hooks/MergeFiles.py b/module/plugins/hooks/MergeFiles.py
index 5d6c208a7..4de45f958 100644
--- a/module/plugins/hooks/MergeFiles.py
+++ b/module/plugins/hooks/MergeFiles.py
@@ -1,53 +1,47 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+from __future__ import with_statement
import os
import re
-import traceback
-from os.path import join
-from module.utils import save_join, fs_encode
-from module.plugins.Hook import Hook, threaded
+from traceback import print_exc
-BUFFER_SIZE = 4096
+from module.plugins.Hook import Hook, threaded
+from module.utils import save_join, fs_encode
class MergeFiles(Hook):
- __name__ = "MergeFiles"
- __version__ = "0.12"
- __type__ = "hook"
+ __name__ = "MergeFiles"
+ __type__ = "hook"
+ __version__ = "0.13"
- __config__ = [("activated", "bool", "Activated", False)]
+ __config__ = [("activated", "bool", "Activated", True)]
__description__ = """Merges parts splitted with hjsplit"""
- __author_name__ = "and9000"
- __author_mail__ = "me@has-no-mail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("and9000", "me@has-no-mail.com")]
+
+
+ BUFFER_SIZE = 4096
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def setup(self):
# nothing to do
pass
+
@threaded
def packageFinished(self, pack):
files = {}
fid_dict = {}
for fid, data in pack.getChildren().iteritems():
- if re.search("\.[0-9]{3}$", data['name']):
+ 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'])
@@ -60,33 +54,36 @@ class MergeFiles(Hook):
download_folder = save_join(download_folder, pack.folder)
for name, file_list in files.iteritems():
- self.logInfo("Starting merging of %s" % name)
- final_file = open(join(download_folder, fs_encode(name)), "wb")
-
- for splitted_file in file_list:
- self.logDebug("Merging part %s" % splitted_file)
- pyfile = self.core.files.getFile(fid_dict[splitted_file])
- pyfile.setStatus("processing")
- try:
- s_file = open(os.path.join(download_folder, splitted_file), "rb")
- size_written = 0
- s_file_size = int(os.path.getsize(os.path.join(download_folder, splitted_file)))
- while True:
- f_buffer = s_file.read(BUFFER_SIZE)
- if f_buffer:
- final_file.write(f_buffer)
- size_written += BUFFER_SIZE
- pyfile.setProgress((size_written * 100) / s_file_size)
- else:
- break
- s_file.close()
- self.logDebug("Finished merging part %s" % splitted_file)
- except Exception, e:
- print traceback.print_exc()
- finally:
- pyfile.setProgress(100)
- pyfile.setStatus("finished")
- pyfile.release()
-
- final_file.close()
- self.logInfo("Finished merging of %s" % name)
+ self.logInfo(_("Starting merging of"), name)
+
+ with open(save_join(download_folder, name), "wb") as final_file:
+ 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(os.path.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/hooks/MultiDebridCom.py b/module/plugins/hooks/MultiDebridCom.py
deleted file mode 100644
index 3309fb9a8..000000000
--- a/module/plugins/hooks/MultiDebridCom.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.MultiHoster import MultiHoster
-from module.network.RequestFactory import getURL
-from module.common.json_layer import json_loads
-
-
-class MultiDebridCom(MultiHoster):
- __name__ = "MultiDebridCom"
- __version__ = "0.01"
- __type__ = "hook"
-
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
- ("hosterList", "str", "Hoster list (comma separated)", ""),
- ("unloadFailing", "bool", "Revert to standard download if download fails", False),
- ("interval", "int", "Reload interval in hours (0 to disable)", 24)]
-
- __description__ = """Multi-debrid.com hook plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
-
- def getHoster(self):
- json_data = getURL('http://multi-debrid.com/api.php?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/MultiHome.py b/module/plugins/hooks/MultiHome.py
index b9c663046..105a42abd 100644
--- a/module/plugins/hooks/MultiHome.py
+++ b/module/plugins/hooks/MultiHome.py
@@ -1,36 +1,25 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from time import time
from module.plugins.Hook import Hook
class MultiHome(Hook):
- __name__ = "MultiHome"
- __version__ = "0.11"
- __type__ = "hook"
+ __name__ = "MultiHome"
+ __type__ = "hook"
+ __version__ = "0.12"
- __config__ = [("activated", "bool", "Activated", False),
- ("interfaces", "str", "Interfaces", "None")]
+ __config__ = [("interfaces", "str", "Interfaces", "None")]
__description__ = """Ip address changer"""
- __author_name__ = "mkaay"
- __author_mail__ = "mkaay@mkaay.de"
+ __license__ = "GPLv3"
+ __authors__ = [("mkaay", "mkaay@mkaay.de")]
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def setup(self):
@@ -41,29 +30,34 @@ class MultiHome(Hook):
self.parseInterfaces([self.config['download']['interface']])
self.setConfig("interfaces", self.toConfig())
+
def toConfig(self):
return ";".join([i.adress for i in self.interfaces])
+
def parseInterfaces(self, interfaces):
for interface in interfaces:
if not interface or str(interface).lower() == "none":
continue
self.interfaces.append(Interface(interface))
+
def coreReady(self):
requestFactory = self.core.requestFactory
oldGetRequest = requestFactory.getRequest
+
def getRequest(pluginName, account=None):
iface = self.bestInterface(pluginName, account)
if iface:
iface.useFor(pluginName, account)
requestFactory.iface = lambda: iface.adress
- self.logDebug("Multihome: using address: " + iface.adress)
+ self.logDebug("Using address", iface.adress)
return oldGetRequest(pluginName, account)
requestFactory.getRequest = getRequest
+
def bestInterface(self, pluginName, account):
best = None
for interface in self.interfaces:
@@ -78,13 +72,16 @@ class Interface(object):
self.adress = adress
self.history = {}
+
def lastPluginAccess(self, pluginName, account):
if (pluginName, account) in self.history:
return self.history[(pluginName, account)]
return 0
+
def useFor(self, pluginName, account):
self.history[(pluginName, account)] = time()
+
def __repr__(self):
return "<Interface - %s>" % self.adress
diff --git a/module/plugins/hooks/MultishareCz.py b/module/plugins/hooks/MultishareCz.py
index 8baa4bb07..5ec5b63b6 100644
--- a/module/plugins/hooks/MultishareCz.py
+++ b/module/plugins/hooks/MultishareCz.py
@@ -3,21 +3,21 @@
import re
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class MultishareCz(MultiHoster):
- __name__ = "MultishareCz"
- __version__ = "0.04"
- __type__ = "hook"
+class MultishareCz(MultiHook):
+ __name__ = "MultishareCz"
+ __type__ = "hook"
+ __version__ = "0.05"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", "uloz.to")]
__description__ = """MultiShare.cz hook plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
HOSTER_PATTERN = r'<img class="logo-shareserveru"[^>]*?alt="([^"]+)"></td>\s*<td class="stav">[^>]*?alt="OK"'
diff --git a/module/plugins/hooks/MyfastfileCom.py b/module/plugins/hooks/MyfastfileCom.py
new file mode 100644
index 000000000..ec7c4e55b
--- /dev/null
+++ b/module/plugins/hooks/MyfastfileCom.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+
+from module.common.json_layer import json_loads
+from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
+
+
+class MyfastfileCom(MultiHook):
+ __name__ = "MyfastfileCom"
+ __type__ = "hook"
+ __version__ = "0.03"
+
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ ("hosterList", "str", "Hoster list (comma separated)", ""),
+ ("unloadFailing", "bool", "Revert to standard download if download fails", False),
+ ("interval", "int", "Reload interval in hours (0 to disable)", 24)]
+
+ __description__ = """Myfastfile.com hook plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
+
+ def getHoster(self):
+ json_data = 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
new file mode 100644
index 000000000..f60cb3dd6
--- /dev/null
+++ b/module/plugins/hooks/NoPremiumPl.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.MultiHoster import MultiHoster
+from module.network.RequestFactory import getURL
+from module.common.json_layer import json_loads as loads
+
+
+class NoPremiumPl(MultiHoster):
+ __name__ = "NoPremiumPl"
+ __version__ = "0.01"
+ __type__ = "hook"
+
+ __config__ = [("activated", "bool", "Activated", "False"),
+ ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
+ ("hosterList", "str", "Hoster list (comma separated)", ""),
+ ("unloadFailing", "bool", "Try standard download if download fails", "False"),
+ ("interval", "int", "Reload supported hosts interval in hours (0 to disable)", "24")]
+
+ __description__ = "NoPremium.pl hook"
+ __license__ = "GPLv3"
+ __authors__ = [("goddie", "dev@nopremium.pl")]
+
+ def getHoster(self):
+ hostings = loads(getURL("https://www.nopremium.pl/clipboard.php?json=3").strip())
+
+ return [domain for row in hostings for domain in row["domains"] if row["sdownload"] == "0"]
+
+ def getHosterCached(self):
+ return self.getHoster()
+
+
diff --git a/module/plugins/hooks/OverLoadMe.py b/module/plugins/hooks/OverLoadMe.py
index dcc57aa75..378ce0a65 100644
--- a/module/plugins/hooks/OverLoadMe.py
+++ b/module/plugins/hooks/OverLoadMe.py
@@ -1,31 +1,29 @@
# -*- coding: utf-8 -*-
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class OverLoadMe(MultiHoster):
- __name__ = "OverLoadMe"
- __version__ = "0.01"
- __type__ = "hook"
+class OverLoadMe(MultiHook):
+ __name__ = "OverLoadMe"
+ __type__ = "hook"
+ __version__ = "0.02"
- __config__ = [("activated", "bool", "Activated", False),
- ("https", "bool", "Enable HTTPS", True),
+ __config__ = [("https", "bool", "Enable HTTPS", True),
("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to standard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 12)]
__description__ = """Over-Load.me hook plugin"""
- __author_name__ = "marley"
- __author_mail__ = "marley@over-load.me"
+ __license__ = "GPLv3"
+ __authors__ = [("marley", "marley@over-load.me")]
def getHoster(self):
https = "https" if self.getConfig("https") else "http"
page = getURL(https + "://api.over-load.me/hoster.php",
- get={"auth": "0001-cb1f24dadb3aa487bda5afd3b76298935329be7700cd7-5329be77-00cf-1ca0135f"}
- ).replace("\"", "").strip()
- self.logDebug("Hosterlist: %s" % page)
+ get={'auth': "0001-cb1f24dadb3aa487bda5afd3b76298935329be7700cd7-5329be77-00cf-1ca0135f"}).replace("\"", "").strip()
+ self.logDebug("Hosterlist", page)
return [x.strip() for x in page.split(",") if x.strip()]
diff --git a/module/plugins/hooks/Premium4Me.py b/module/plugins/hooks/Premium4Me.py
deleted file mode 100644
index 242e72f3e..000000000
--- a/module/plugins/hooks/Premium4Me.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
-
-
-class Premium4Me(MultiHoster):
- __name__ = "Premium4Me"
- __version__ = "0.03"
- __type__ = "hook"
-
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for downloads from supported hosters:", "all"),
- ("hosterList", "str", "Hoster list (comma separated)", "")]
-
- __description__ = """Premium.to hook plugin"""
- __author_name__ = ("RaNaN", "zoidberg", "stickell")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz", "l.stickell@yahoo.it")
-
-
- def getHoster(self):
- page = getURL("http://premium.to/api/hosters.php?authcode=%s" % self.account.authcode)
- return [x.strip() for x in page.replace("\"", "").split(";")]
-
- def coreReady(self):
- self.account = self.core.accountManager.getAccountPlugin("Premium4Me")
-
- user = self.account.selectAccount()[0]
-
- if not user:
- self.logError(_("Please add your premium.to account first and restart pyLoad"))
- return
-
- return MultiHoster.coreReady(self)
diff --git a/module/plugins/hooks/PremiumTo.py b/module/plugins/hooks/PremiumTo.py
new file mode 100644
index 000000000..3087db552
--- /dev/null
+++ b/module/plugins/hooks/PremiumTo.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+
+from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
+
+
+class PremiumTo(MultiHook):
+ __name__ = "PremiumTo"
+ __type__ = "hook"
+ __version__ = "0.05"
+
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for downloads from supported hosters:", "all"),
+ ("hosterList", "str", "Hoster list (comma separated)", "")]
+
+ __description__ = """Premium.to hook plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
+
+ def getHoster(self):
+ page = getURL("http://premium.to/api/hosters.php",
+ get={'username': self.account.username, 'password': self.account.password})
+ return [x.strip() for x in page.replace("\"", "").split(";")]
+
+
+ def coreReady(self):
+ self.account = self.core.accountManager.getAccountPlugin("PremiumTo")
+
+ user = self.account.selectAccount()[0]
+
+ if not user:
+ self.logError(_("Please add your premium.to account first and restart pyLoad"))
+ return
+
+ return MultiHook.coreReady(self)
diff --git a/module/plugins/hooks/PremiumizeMe.py b/module/plugins/hooks/PremiumizeMe.py
index 1a35460de..b37728e06 100644
--- a/module/plugins/hooks/PremiumizeMe.py
+++ b/module/plugins/hooks/PremiumizeMe.py
@@ -1,25 +1,23 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.MultiHoster import MultiHoster
-
from module.common.json_layer import json_loads
from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
-class PremiumizeMe(MultiHoster):
- __name__ = "PremiumizeMe"
- __version__ = "0.12"
- __type__ = "hook"
+class PremiumizeMe(MultiHook):
+ __name__ = "PremiumizeMe"
+ __type__ = "hook"
+ __version__ = "0.14"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to stanard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """Premiumize.me hook plugin"""
- __author_name__ = "Florian Franzen"
- __author_mail__ = "FlorianFranzen@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Florian Franzen", "FlorianFranzen@gmail.com")]
def getHoster(self):
@@ -32,24 +30,25 @@ class PremiumizeMe(MultiHoster):
# Get supported hosters list from premiumize.me using the
# json API v1 (see https://secure.premiumize.me/?show=api)
- answer = getURL("https://api.premiumize.me/pm-api/v1.php?method=hosterlist&params[login]=%s&params[pass]=%s" % (
- user, data['password']))
+ answer = 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
+ # Extract hosters from json file
return data['result']['hosterlist']
+
def coreReady(self):
# Get account plugin and check if there is a valid account available
self.account = self.core.accountManager.getAccountPlugin("PremiumizeMe")
if not self.account.canUse():
self.account = None
- self.logError(_("Please add a valid premiumize.me account first and restart pyLoad."))
+ self.logError(_("Please add a valid premiumize.me account first and restart pyLoad"))
return
- # Run the overwriten core ready which actually enables the multihoster hook
- return MultiHoster.coreReady(self)
+ # Run the overwriten core ready which actually enables the multihoster hook
+ return MultiHook.coreReady(self)
diff --git a/module/plugins/hooks/RPNetBiz.py b/module/plugins/hooks/RPNetBiz.py
index 36cf69b4b..c54f7d445 100644
--- a/module/plugins/hooks/RPNetBiz.py
+++ b/module/plugins/hooks/RPNetBiz.py
@@ -1,24 +1,23 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.MultiHoster import MultiHoster
from module.common.json_layer import json_loads
from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
-class RPNetBiz(MultiHoster):
- __name__ = "RPNetBiz"
- __version__ = "0.1"
- __type__ = "hook"
+class RPNetBiz(MultiHook):
+ __name__ = "RPNetBiz"
+ __type__ = "hook"
+ __version__ = "0.11"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to stanard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """RPNet.biz hook plugin"""
- __author_name__ = "Dman"
- __author_mail__ = "dmanugm@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Dman", "dmanugm@gmail.com")]
def getHoster(self):
@@ -29,17 +28,18 @@ class RPNetBiz(MultiHoster):
# Get account data
(user, data) = self.account.selectAccount()
- response = getURL("https://premium.rpnet.biz/client_api.php",
- get={"username": user, "password": data['password'], "action": "showHosterList"})
- hoster_list = json_loads(response)
+ res = 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
+ # Extract hosters from json file
return hoster_list['hosters']
+
def coreReady(self):
# Get account plugin and check if there is a valid account available
self.account = self.core.accountManager.getAccountPlugin("RPNetBiz")
@@ -48,5 +48,5 @@ class RPNetBiz(MultiHoster):
self.logError(_("Please enter your %s account or deactivate this plugin") % "rpnet")
return
- # Run the overwriten core ready which actually enables the multihoster hook
- return MultiHoster.coreReady(self)
+ # Run the overwriten core ready which actually enables the multihoster hook
+ return MultiHook.coreReady(self)
diff --git a/module/plugins/hooks/RapideoPl.py b/module/plugins/hooks/RapideoPl.py
new file mode 100644
index 000000000..a5d7a34a5
--- /dev/null
+++ b/module/plugins/hooks/RapideoPl.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.MultiHoster import MultiHoster
+from module.network.RequestFactory import getURL
+from module.common.json_layer import json_loads as loads
+
+
+class RapideoPl(MultiHoster):
+ __name__ = "RapideoPl"
+ __version__ = "0.01"
+ __type__ = "hook"
+
+ __config__ = [("activated", "bool", "Activated", "False"),
+ ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
+ ("hosterList", "str", "Hoster list (comma separated)", ""),
+ ("unloadFailing", "bool", "Try standard download if download fails", "False"),
+ ("interval", "int", "Reload supported hosts interval in hours (0 to disable)", "24")]
+
+ __description__ = "Rapideo.pl hook"
+ __license__ = "GPLv3"
+ __authors__ = [("goddie", "dev@rapideo.pl")]
+
+ def getHoster(self):
+ hostings = loads(getURL("https://www.rapideo.pl/clipboard.php?json=3").strip())
+
+ return [domain for row in hostings for domain in row["domains"] if row["sdownload"] == "0"]
+
+ def getHosterCached(self):
+ return self.getHoster()
+
+
diff --git a/module/plugins/hooks/RealdebridCom.py b/module/plugins/hooks/RealdebridCom.py
index 4477fba4a..066aa52c4 100644
--- a/module/plugins/hooks/RealdebridCom.py
+++ b/module/plugins/hooks/RealdebridCom.py
@@ -1,24 +1,23 @@
# -*- coding: utf-8 -*-
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class RealdebridCom(MultiHoster):
- __name__ = "RealdebridCom"
- __version__ = "0.43"
- __type__ = "hook"
+class RealdebridCom(MultiHook):
+ __name__ = "RealdebridCom"
+ __type__ = "hook"
+ __version__ = "0.44"
- __config__ = [("activated", "bool", "Activated", False),
- ("https", "bool", "Enable HTTPS", False),
+ __config__ = [("https", "bool", "Enable HTTPS", False),
("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to stanard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """Real-Debrid.com hook plugin"""
- __author_name__ = "Devirex Hazzard"
- __author_mail__ = "naibaf_11@yahoo.de"
+ __license__ = "GPLv3"
+ __authors__ = [("Devirex Hazzard", "naibaf_11@yahoo.de")]
def getHoster(self):
diff --git a/module/plugins/hooks/RehostTo.py b/module/plugins/hooks/RehostTo.py
index 96e06950e..48afa2342 100644
--- a/module/plugins/hooks/RehostTo.py
+++ b/module/plugins/hooks/RehostTo.py
@@ -1,40 +1,41 @@
# -*- coding: utf-8 -*-
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class RehostTo(MultiHoster):
- __name__ = "RehostTo"
- __version__ = "0.43"
- __type__ = "hook"
+class RehostTo(MultiHook):
+ __name__ = "RehostTo"
+ __type__ = "hook"
+ __version__ = "0.44"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to stanard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24)]
__description__ = """Rehost.to hook plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
def getHoster(self):
- page = getURL("http://rehost.to/api.php?cmd=get_supported_och_dl&long_ses=%s" % self.long_ses)
+ page = getURL("http://rehost.to/api.php",
+ get={'cmd': "get_supported_och_dl", 'long_ses': self.long_ses})
return [x.strip() for x in page.replace("\"", "").split(",")]
+
def coreReady(self):
self.account = self.core.accountManager.getAccountPlugin("RehostTo")
user = self.account.selectAccount()[0]
if not user:
- self.logError("Rehost.to: " + _("Please add your rehost.to account first and restart pyLoad"))
+ self.logError(_("Please add your rehost.to account first and restart pyLoad"))
return
data = self.account.getAccountInfo(user)
self.ses = data['ses']
self.long_ses = data['long_ses']
- return MultiHoster.coreReady(self)
+ return MultiHook.coreReady(self)
diff --git a/module/plugins/hooks/RestartFailed.py b/module/plugins/hooks/RestartFailed.py
index 2bd0e28db..07fb80967 100644
--- a/module/plugins/hooks/RestartFailed.py
+++ b/module/plugins/hooks/RestartFailed.py
@@ -1,37 +1,23 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
from module.plugins.Hook import Hook
class RestartFailed(Hook):
- __name__ = "RestartFailed"
- __version__ = "1.55"
- __type__ = "hook"
+ __name__ = "RestartFailed"
+ __type__ = "hook"
+ __version__ = "1.57"
- __config__ = [("activated", "bool", "Activated", False),
- ("interval", "int", "Check interval in minutes", 90)]
+ __config__ = [("interval", "int", "Check interval in minutes", 90)]
__description__ = """Periodically restart all failed downloads in queue"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- MIN_INTERVAL = 15 * 60 #: 15m minimum check interval (value is in seconds)
- event_list = ["pluginConfigChanged"]
+ # event_list = ["pluginConfigChanged"]
+
+ MIN_INTERVAL = 15 * 60 #: 15m minimum check interval (value is in seconds)
def pluginConfigChanged(self, plugin, name, value):
@@ -44,13 +30,15 @@ class RestartFailed(Hook):
else:
self.logDebug("Invalid interval value, kept current")
+
def periodical(self):
- self.logInfo("Restart failed downloads")
- self.api.restartFailed()
+ self.logDebug(_("Restart failed downloads"))
+ self.core.api.restartFailed()
+
def setup(self):
- self.api = self.core.api
self.interval = self.MIN_INTERVAL
+
def coreReady(self):
self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval"))
diff --git a/module/plugins/hooks/RestartSlow.py b/module/plugins/hooks/RestartSlow.py
new file mode 100644
index 000000000..c2fdf6f95
--- /dev/null
+++ b/module/plugins/hooks/RestartSlow.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+
+import pycurl
+
+from module.plugins.Hook import Hook
+
+
+class RestartSlow(Hook):
+ __name__ = "RestartSlow"
+ __type__ = "hook"
+ __version__ = "0.03"
+
+ __config__ = [("free_limit" , "int" , "Transfer speed threshold in kilobytes" , 100 ),
+ ("free_time" , "int" , "Sample interval in minutes" , 5 ),
+ ("premium_limit", "int" , "Transfer speed threshold for premium download in kilobytes", 300 ),
+ ("premium_time" , "int" , "Sample interval for premium download in minutes" , 2 ),
+ ("safe_mode" , "bool", "Don't restart if download is not resumable" , True)]
+
+ __description__ = """Restart slow downloads"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ event_list = ["downloadStarts"]
+
+
+ def setup(self):
+ self.info = {'chunk': {}}
+
+
+ def initPeriodical(self):
+ pass
+
+
+ def periodical(self):
+ if not self.pyfile.req.dl:
+ return
+
+ if self.getConfig("safe_mode") and not self.pyfile.plugin.resumeDownload:
+ time = 30
+ limit = 5
+ else:
+ type = "premium" if self.pyfile.plugin.premium else "free"
+ time = max(30, self.getConfig("%s_time" % type) * 60)
+ limit = max(5, self.getConfig("%s_limit" % type) * 1024)
+
+ chunks = [chunk for chunk in self.pyfile.req.dl.chunks \
+ if chunk.id not in self.info['chunk'] or self.info['chunk'][chunk.id] is not (time, limit)]
+
+ for chunk in chunks:
+ chunk.c.setopt(pycurl.LOW_SPEED_TIME , time)
+ chunk.c.setopt(pycurl.LOW_SPEED_LIMIT, limit)
+
+ self.info['chunk'][chunk.id] = (time, limit)
+
+
+ def downloadStarts(self, pyfile, url, filename):
+ if self.cb or (self.getConfig("safe_mode") and not pyfile.plugin.resumeDownload):
+ return
+
+ super(RestartSlow, self).initPeriodical()
diff --git a/module/plugins/hooks/SimplyPremiumCom.py b/module/plugins/hooks/SimplyPremiumCom.py
index 41268e231..10a1655c2 100644
--- a/module/plugins/hooks/SimplyPremiumCom.py
+++ b/module/plugins/hooks/SimplyPremiumCom.py
@@ -1,28 +1,14 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
from module.common.json_layer import json_loads
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class SimplyPremiumCom(MultiHoster):
- __name__ = "SimplyPremiumCom"
- __version__ = "0.02"
- __type__ = "hook"
+class SimplyPremiumCom(MultiHook):
+ __name__ = "SimplyPremiumCom"
+ __type__ = "hook"
+ __version__ = "0.03"
__config__ = [("activated", "bool", "Activated", "False"),
("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
@@ -31,12 +17,12 @@ class SimplyPremiumCom(MultiHoster):
("interval", "int", "Reload interval in hours (0 to disable)", "24")]
__description__ = """Simply-Premium.com hook plugin"""
- __author_name__ = "EvolutionClip"
- __author_mail__ = "evolutionclip@live.de"
+ __license__ = "GPLv3"
+ __authors__ = [("EvolutionClip", "evolutionclip@live.de")]
def getHoster(self):
- json_data = getURL('http://www.simply-premium.com/api/hosts.php?format=json&online=1')
+ json_data = 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']]
diff --git a/module/plugins/hooks/SimplydebridCom.py b/module/plugins/hooks/SimplydebridCom.py
index 345d37e4a..48568f870 100644
--- a/module/plugins/hooks/SimplydebridCom.py
+++ b/module/plugins/hooks/SimplydebridCom.py
@@ -1,23 +1,22 @@
# -*- coding: utf-8 -*-
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class SimplydebridCom(MultiHoster):
- __name__ = "SimplydebridCom"
- __version__ = "0.01"
- __type__ = "hook"
+class SimplydebridCom(MultiHook):
+ __name__ = "SimplydebridCom"
+ __type__ = "hook"
+ __version__ = "0.02"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", "")]
__description__ = """Simply-Debrid.com hook plugin"""
- __author_name__ = "Kagenoshin"
- __author_mail__ = "kagenoshin@gmx.ch"
+ __license__ = "GPLv3"
+ __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")]
def getHoster(self):
- page = getURL("http://simply-debrid.com/api.php?list=1")
+ page = getURL("http://simply-debrid.com/api.php", get={'list': 1})
return [x.strip() for x in page.rstrip(';').replace("\"", "").split(";")]
diff --git a/module/plugins/hooks/SkipRev.py b/module/plugins/hooks/SkipRev.py
new file mode 100644
index 000000000..cc32c365e
--- /dev/null
+++ b/module/plugins/hooks/SkipRev.py
@@ -0,0 +1,108 @@
+# -*- 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.21"
+
+ __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):
+ url = pyfile.url
+ plugin = pyfile.plugin
+
+ if hasattr(plugin, "info") and 'name' in plugin.info and plugin.info['name']:
+ name = plugin.info['name']
+
+ elif hasattr(plugin, "parseInfos"):
+ name = next(plugin.parseInfos([url]))['name']
+
+ elif hasattr(plugin, "getInfo"): #@NOTE: if parseInfos was not found, getInfo should be missing too
+ name = plugin.getInfo(url)['name']
+
+ else:
+ self.logWarning("Unable to grab file name")
+ name = urlparse(unquote(url)).path.split('/')[-1]
+
+ return name
+
+
+ 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:
+ saved = [True for link in self.core.api.getPackageData(pyfile.package().id).links \
+ if link.name.endswith(".rev") and link.status in (0, 12)].count(True)
+
+ if not saved or saved < 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/hooks/UnSkipOnFail.py b/module/plugins/hooks/UnSkipOnFail.py
index d40854e99..1becb937a 100644
--- a/module/plugins/hooks/UnSkipOnFail.py
+++ b/module/plugins/hooks/UnSkipOnFail.py
@@ -1,99 +1,95 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-from os.path import basename
-
-from module.utils import fs_encode
-from module.plugins.Hook import Hook
from module.PyFile import PyFile
+from module.plugins.Hook import Hook
class UnSkipOnFail(Hook):
- __name__ = "UnSkipOnFail"
- __version__ = "0.01"
- __type__ = "hook"
+ __name__ = "UnSkipOnFail"
+ __type__ = "hook"
+ __version__ = "0.05"
__config__ = [("activated", "bool", "Activated", True)]
- __description__ = """When a download fails, restart skipped duplicates"""
- __author_name__ = "hagg"
- __author_mail__ = None
+ __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):
- pyfile_name = basename(pyfile.name)
- pid = pyfile.package().id
- msg = 'look for skipped duplicates for %s (pid:%s)...'
- self.logInfo(msg % (pyfile_name, pid))
- dups = self.findDuplicates(pyfile)
- for link in dups:
- # check if link is "skipped"(=4)
- if link.status == 4:
- lpid = link.packageID
- self.logInfo('restart "%s" (pid:%s)...' % (pyfile_name, lpid))
- self.setLinkStatus(link, "queued")
-
- def findDuplicates(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 (basename(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.
"""
- dups = []
- pyfile_name = fs_encode(basename(pyfile.name))
- # get packages (w/o files, as most file data is useless here)
- queue = self.core.api.getQueue()
+ 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 fs_encode(package.folder) == fs_encode(pyfile.package().folder):
- # now get packaged data w/ files/links
- pdata = self.core.api.getPackageData(package.pid)
- if pdata.links:
- for link in pdata.links:
- link_name = fs_encode(basename(link.name))
- # check if link name collides with pdata's name
- if link_name == pyfile_name:
- # at last check if it is not pyfile itself
- if link.fid != pyfile.id:
- dups.append(link)
- return dups
-
- def setLinkStatus(self, link, new_status):
- """ 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.
- """
- pyfile = PyFile(self.core.files,
- link.fid,
- link.url,
- link.name,
- link.size,
- link.status,
- link.error,
- link.plugin,
- link.packageID,
- link.order)
- pyfile.setStatus(new_status)
- self.core.files.save()
- pyfile.release()
+ #: 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/hooks/UnrestrictLi.py b/module/plugins/hooks/UnrestrictLi.py
index 3303c7355..245264d44 100644
--- a/module/plugins/hooks/UnrestrictLi.py
+++ b/module/plugins/hooks/UnrestrictLi.py
@@ -1,43 +1,28 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-from module.plugins.internal.MultiHoster import MultiHoster
-from module.network.RequestFactory import getURL
+
from module.common.json_layer import json_loads
+from module.network.RequestFactory import getURL
+from module.plugins.internal.MultiHook import MultiHook
-class UnrestrictLi(MultiHoster):
- __name__ = "UnrestrictLi"
- __version__ = "0.02"
- __type__ = "hook"
+class UnrestrictLi(MultiHook):
+ __name__ = "UnrestrictLi"
+ __type__ = "hook"
+ __version__ = "0.03"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", ""),
("unloadFailing", "bool", "Revert to standard download if download fails", False),
("interval", "int", "Reload interval in hours (0 to disable)", 24),
("history", "bool", "Delete History", False)]
__description__ = """Unrestrict.li hook plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
def getHoster(self):
- json_data = getURL('http://unrestrict.li/api/jdownloader/hosts.php?format=json')
+ json_data = getURL("http://unrestrict.li/api/jdownloader/hosts.php", get={'format': "json"})
json_data = json_loads(json_data)
host_list = [element['host'] for element in json_data['result']]
diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py
index 6ed756d13..c72699228 100644
--- a/module/plugins/hooks/UpdateManager.py
+++ b/module/plugins/hooks/UpdateManager.py
@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
import re
import sys
from operator import itemgetter
-from os import remove, stat
-from os.path import isfile
-from time import time
+from os import path, remove, stat
from module.network.RequestFactory import getURL
from module.plugins.Hook import Expose, Hook, threaded
@@ -14,23 +14,26 @@ from module.utils import save_join
class UpdateManager(Hook):
- __name__ = "UpdateManager"
- __version__ = "0.33"
- __type__ = "hook"
+ __name__ = "UpdateManager"
+ __type__ = "hook"
+ __version__ = "0.42"
+
+ __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" , True )]
- __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")]
- __description__ = """Check for updates"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
- event_list = ["pluginConfigChanged"]
+ # event_list = ["pluginConfigChanged"]
- SERVER_URL = "http://updatemanager.pyload.org"
+ 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)
@@ -38,33 +41,43 @@ class UpdateManager(Hook):
if name == "interval":
interval = value * 60 * 60
if self.MIN_INTERVAL <= interval != self.interval:
- self.scheduler.removeJob(self.cb)
+ 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.scheduler.removeJob(self.cb2)
+ self.core.scheduler.removeJob(self.cb2)
if value is True and self.core.debug:
self.periodical2()
+
def coreReady(self):
self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval"))
- self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins"))
+ x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins"))
+ self.core.scheduler.addJob(10, x, threaded=False)
+
+
+ def unload(self):
+ self.pluginConfigChanged(self.__name__, "reloadplugins", False)
+
def setup(self):
- self.scheduler = self.core.scheduler
- self.cb2 = None
+ 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
+ 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.scheduler.addJob(10, self.periodical2, threaded=False)
+
+ self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False)
+
@Expose
def autoreloadPlugins(self):
@@ -82,7 +95,7 @@ class UpdateManager(Hook):
id = (type, name)
if type in self.core.pluginManager.plugins:
f = m.__file__.replace(".pyc", ".py")
- if not isfile(f):
+ if not path.isfile(f):
continue
mtime = stat(f).st_mtime
@@ -95,42 +108,53 @@ class UpdateManager(Hook):
return True if self.core.pluginManager.reloadPlugins(reloads) else False
+
def periodical(self):
if not self.info['pyload'] and not (self.getConfig("nodebugupdate") and self.core.debug):
self.updateThread()
+
def server_request(self):
try:
return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines()
except:
self.logWarning(_("Unable to contact server to get updates"))
+
@threaded
def updateThread(self):
self.updating = True
- status = self.update(onlyplugin=True if self.getConfig("mode") == "plugins only" else False)
- if status == 2:
+
+ 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)
@@ -138,38 +162,62 @@ class UpdateManager(Hook):
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
- updated = []
+ exitcode = 0
+ updated = []
- vre = re.compile(r'__version__.*=.*("|\')([0-9.]+)')
- url = updates[0]
+ url = updates[0]
schema = updates[1].split('|')
+
if "BLACKLIST" in updates:
blacklist = updates[updates.index('BLACKLIST') + 1:]
- updates = updates[2:updates.index('BLACKLIST')]
+ updates = updates[2:updates.index('BLACKLIST')]
else:
blacklist = None
- updates = updates[2:]
+ 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:
+ 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,
+ })
- upgradable = sorted(map(lambda x: dict(zip(schema, x.split('|'))), updates), key=itemgetter("type", "name"))
- for plugin in upgradable:
+ for plugin in sorted(upgradable, key=itemgetter("type", "name")):
filename = plugin['name']
- prefix = plugin['type']
- version = plugin['version']
+ prefix = plugin['type']
+ version = plugin['version']
if filename.endswith(".pyc"):
name = filename[:filename.find("_")]
else:
name = filename.replace(".py", "")
- #TODO: obsolete in 0.5.0
+ #@TODO: obsolete after 0.4.10
if prefix.endswith("s"):
type = prefix[:-1]
else:
@@ -181,47 +229,30 @@ class UpdateManager(Hook):
newver = float(version)
if not oldver:
- msg = "New version of [%(type)s] %(name)s (v%(newver)s)"
+ msg = "New plugin: [%(type)s] %(name)s (v%(newver).2f)"
elif newver > oldver:
- msg = "New version of [%(type)s] %(name)s (v%(oldver)s -> v%(newver)s)"
+ 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
- })
-
+ self.logInfo(_(msg) % {'type' : type,
+ 'name' : name,
+ 'oldver': oldver,
+ 'newver': newver})
try:
content = getURL(url % plugin)
- m = vre.search(content)
+ m = self.VERSION.search(content)
+
if m and m.group(2) == version:
- f = open(save_join("userplugins", prefix, filename), "wb")
- f.write(content)
- f.close()
+ with open(save_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 blacklist:
- blacklisted = sorted(map(lambda x: (x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]), blacklist))
+ raise Exception, _("Version mismatch")
- # Always protect UpdateManager from self-removing
- try:
- blacklisted.remove(("hook", "UpdateManager"))
- except:
- pass
-
- removed = self.removePlugins(blacklisted)
- for t, n in removed:
- self.logInfo(_("Removed blacklisted plugin [%(type)s] %(name)s") % {
- "type": t,
- "name": n
- })
+ except Exception, e:
+ self.logError(_("Error updating plugin: %s") % filename, str(e))
if updated:
reloaded = self.core.pluginManager.reloadPlugins(updated)
@@ -234,47 +265,45 @@ class UpdateManager(Hook):
exitcode = 2
else:
self.logInfo(_("No plugin updates available"))
- exitcode = 0
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"""
+ """ delete plugins from disk """
if not type_plugins:
- return None
+ return
- self.logDebug("Request deletion of plugins: %s" % type_plugins)
+ self.logDebug("Requested deletion of plugins: %s" % type_plugins)
removed = []
for type, name in type_plugins:
- rflag = False
- py_file = name + ".py"
- pyc_file = name + ".pyc"
+ err = False
+ file = name + ".py"
- for root in ("userplugins", save_join(pypath, "module", "plugins")):
- py_filename = save_join(root, type, py_file)
- pyc_filename = save_join(root, type, pyc_file)
+ for root in ("userplugins", path.join(pypath, "module", "plugins")):
- if isfile(py_filename):
- try:
- remove(py_filename)
- except Exception, e:
- self.logError("Error deleting file %s" % py_filename, str(e))
- rflag = False
- else:
- rflag = True
+ filename = save_join(root, type, file)
+ try:
+ remove(filename)
+ except Exception, e:
+ self.logDebug("Error removing: %s" % path.basename(filename), str(e))
+ err = True
- if isfile(pyc_filename):
+ filename += "c"
+ if path.isfile(filename):
try:
if type == "hook":
self.manager.deactivateHook(name)
- remove(pyc_filename)
+ remove(filename)
except Exception, e:
- self.logError("Error deleting file %s" % pyc_filename, str(e))
- if rflag:
+ self.logDebug("Error removing: %s" % path.basename(filename), str(e))
+ err = True
+
+ if not err:
id = (type, name)
removed.append(id)
diff --git a/module/plugins/hooks/WindowsPhoneToastNotify.py b/module/plugins/hooks/WindowsPhoneToastNotify.py
index 25fa3abe5..ed305778c 100644
--- a/module/plugins/hooks/WindowsPhoneToastNotify.py
+++ b/module/plugins/hooks/WindowsPhoneToastNotify.py
@@ -1,42 +1,34 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-import time
import httplib
+import time
+
from module.plugins.Hook import Hook
class WindowsPhoneToastNotify(Hook):
- __name__ = "WindowsPhoneToastNotify"
- __version__ = "0.02"
- __type__ = "hook"
+ __name__ = "WindowsPhoneToastNotify"
+ __type__ = "hook"
+ __version__ = "0.03"
- __config__ = [("activated", "bool", "Activated", False),
- ("force", "bool", "Force even if client is connected", False),
+ __config__ = [("force", "bool", "Force even if client is connected", False),
("pushId", "str", "pushId", ""),
("pushUrl", "str", "pushUrl", ""),
("pushTimeout", "int", "Timeout between notifications in seconds", 0)]
__description__ = """Send push notifications to Windows Phone"""
- __author_name__ = "Andy Voigt"
- __author_mail__ = "phone-support@hotmail.de"
+ __license__ = "GPLv3"
+ __authors__ = [("Andy Voigt", "phone-support@hotmail.de")]
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def setup(self):
- self.info = {}
+ self.info = {} #@TODO: Remove in 0.4.10
+
def getXmlData(self):
myxml = ("<?xml version='1.0' encoding='utf-8'?> <wp:Notification xmlns:wp='WPNotification'> "
@@ -44,6 +36,7 @@ class WindowsPhoneToastNotify(Hook):
"</wp:Toast> </wp:Notification>")
return myxml
+
def doRequest(self):
URL = self.getConfig("pushUrl")
request = self.getXmlData()
@@ -59,6 +52,7 @@ class WindowsPhoneToastNotify(Hook):
webservice.close()
self.setStorage("LAST_NOTIFY", time.time())
+
def newCaptchaTask(self, task):
if not self.getConfig("pushId") or not self.getConfig("pushUrl"):
return False
diff --git a/module/plugins/hooks/XFileSharingPro.py b/module/plugins/hooks/XFileSharingPro.py
index 37a464b33..589143547 100644
--- a/module/plugins/hooks/XFileSharingPro.py
+++ b/module/plugins/hooks/XFileSharingPro.py
@@ -6,73 +6,126 @@ from module.plugins.Hook import Hook
class XFileSharingPro(Hook):
- __name__ = "XFileSharingPro"
- __version__ = "0.11"
- __type__ = "hook"
+ __name__ = "XFileSharingPro"
+ __type__ = "hook"
+ __version__ = "0.28"
- __config__ = [("activated", "bool", "Activated", True),
- ("loadDefault", "bool", "Include default (built-in) hoster list", True),
- ("includeList", "str", "Include hosters (comma separated)", ""),
- ("excludeList", "str", "Exclude hosters (comma separated)", "")]
+ __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__ = """XFileSharingPro hook plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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\.)?([\w.^_]+(?:\.[a-zA-Z]{2,})(?:\:\d+)?)/(?:embed-)?\w{12}(?:\W|$)',
+ r'https?://(?:[^/]+\.)?(%s)/(?:embed-)?\w+'),
+ 'crypter': (r'https?://(?:www\.)?([\w.^_]+(?:\.[a-zA-Z]{2,})(?:\:\d+)?)/(?:user|folder)s?/\w+',
+ r'https?://(?:[^/]+\.)?(%s)/(?:user|folder)s?/\w+')}
+
+ HOSTER_LIST = [#WORKING HOSTERS:
+ "eyesfile.ca", "file4safe.com", "fileband.com", "filedwon.com", "filevice.com", "hostingbulk.com",
+ "ravishare.com", "salefiles.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_LIST = []
+
+
+ # def pluginConfigChanged(self.__name__, plugin, name, value):
+ # self.loadPattern()
+
+
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
def coreReady(self):
self.loadPattern()
+
def loadPattern(self):
- hosterList = self.getConfigSet('includeList')
- excludeList = self.getConfigSet('excludeList')
-
- if self.getConfig('loadDefault'):
- hosterList |= set((
- #WORKING HOSTERS:
- "aieshare.com", "asixfiles.com", "banashare.com", "cyberlocker.ch", "eyesfile.co", "eyesfile.com",
- "fileband.com", "filedwon.com", "filedownloads.org", "hipfile.com", "kingsupload.com", "mlfat4arab.com",
- "netuploaded.com", "odsiebie.pl", "q4share.com", "ravishare.com", "uptobox.com", "verzend.be",
- "xvidstage.com", "thefile.me", "sharesix.com", "hostingbulk.com",
- #NOT TESTED:
- "bebasupload.com", "boosterking.com", "divxme.com", "filevelocity.com", "glumbouploads.com",
- "grupload.com", "heftyfile.com", "host4desi.com", "laoupload.com", "linkzhost.com", "movreel.com",
- "rockdizfile.com", "limfile.com", "share76.com", "sharebeast.com", "sharehut.com", "sharerun.com",
- "shareswift.com", "sharingonline.com", "6ybh-upload.com", "skipfile.com", "spaadyshare.com",
- "space4file.com", "uploadbaz.com", "uploadc.com", "uploaddot.com", "uploadfloor.com", "uploadic.com",
- "uploadville.com", "vidbull.com", "zalaa.com", "zomgupload.com", "kupload.org", "movbay.org",
- "multishare.org", "omegave.org", "toucansharing.org", "uflinq.org", "banicrazy.info", "flowhot.info",
- "upbrasil.info", "shareyourfilez.biz", "bzlink.us", "cloudcache.cc", "fileserver.cc", "farshare.to",
- "filemaze.ws", "filehost.ws", "filestock.ru", "moidisk.ru", "4up.im", "100shared.com", "sharesix.com",
- "thefile.me", "filenuke.com", "sharerepo.com", "mightyupload.com",
- #WRONG FILE NAME:
- "sendmyway.com", "upchi.co.il",
- #NOT WORKING:
- "amonshare.com", "imageporter.com", "file4safe.com",
- #DOWN OR BROKEN:
- "ddlanime.com", "fileforth.com", "loombo.com", "goldfile.eu", "putshare.com"
- ))
-
- hosterList -= (excludeList)
- hosterList -= set(('', u''))
-
- if not hosterList:
- self.unload()
- return
-
- regexp = r"http://(?:[^/]*\.)?(%s)/\w{12}" % ("|".join(sorted(hosterList)).replace('.', '\.'))
- #self.logDebug(regexp)
-
- dict = self.core.pluginManager.hosterPlugins['XFileSharingPro']
- dict['pattern'] = regexp
- dict['re'] = re.compile(regexp)
- self.logDebug("Pattern loaded - handling %d hosters" % len(hosterList))
-
- def getConfigSet(self, option):
- s = self.getConfig(option).lower().replace('|', ',').replace(';', ',')
- return set([x.strip() for x in s.split(',')])
+ use_builtin_list = self.getConfig('use_builtin_list')
- def unload(self):
- dict = self.core.pluginManager.hosterPlugins['XFileSharingPro']
+ for type, plugin in (("hoster", "XFileSharingPro"),
+ ("crypter", "XFileSharingProFolder")):
+ 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:
+ s = self.getConfig('%s_list' % type).replace('\\', '').replace('|', ',').replace(';', ',').lower()
+ plugin_list = set([x.strip() for x in s.split(',')])
+
+ if use_builtin_list:
+ plugin_list |= set([x.lower() for x in getattr(self, "%s_LIST" % type.upper())])
+
+ plugin_list -= set(('', u''))
+
+ if not plugin_list:
+ self.logInfo(_("No %s to handle") % type)
+ self._unload(type, plugin)
+ return
+
+ match_list = '|'.join(sorted(plugin_list))
+
+ len_match_list = len(plugin_list)
+ self.logInfo(_("Handling %d %s%s: %s") % (len_match_list,
+ type,
+ "" if len_match_list is 1 else "s",
+ match_list.replace('|', ', ')))
+
+ pattern = self.regexp[type][1] % match_list.replace('.', '\.')
+
+ dict = self.core.pluginManager.plugins[type][plugin]
+ dict['pattern'] = pattern
+ dict['re'] = re.compile(pattern)
+
+ self.logDebug("Loaded %s pattern: %s" % (type, pattern))
+
+
+ def _unload(self, type, plugin):
+ dict = self.core.pluginManager.plugins[type][plugin]
dict['pattern'] = r'^unmatchable$'
- dict['re'] = re.compile(r'^unmatchable$')
+ dict['re'] = re.compile(dict['pattern'])
+
+
+ def unload(self):
+ # self.unloadHoster("BasePlugin")
+ for type, plugin in (("hoster", "XFileSharingPro"),
+ ("crypter", "XFileSharingProFolder")):
+ self._unload(type, plugin)
+
+
+ def unloadHoster(self, hoster):
+ hdict = self.core.pluginManager.hosterPlugins[hoster]
+ if "new_name" in hdict and hdict['new_name'] is "XFileSharingPro":
+ if "module" in hdict:
+ del hdict['module']
+
+ if "new_module" in hdict:
+ del hdict['new_module']
+ del hdict['new_name']
+
+ return True
+ else:
+ return False
+
+
+ # def downloadFailed(self, pyfile):
+ # if pyfile.pluginname is "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/XMPPInterface.py b/module/plugins/hooks/XMPPInterface.py
index a60d31b89..bbeab4341 100644
--- a/module/plugins/hooks/XMPPInterface.py
+++ b/module/plugins/hooks/XMPPInterface.py
@@ -1,36 +1,20 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from pyxmpp import streamtls
from pyxmpp.all import JID, Message
-from pyxmpp.jabber.client import JabberClient
from pyxmpp.interface import implements
from pyxmpp.interfaces import *
+from pyxmpp.jabber.client import JabberClient
from module.plugins.hooks.IRCInterface import IRCInterface
class XMPPInterface(IRCInterface, JabberClient):
- __name__ = "XMPPInterface"
+ __name__ = "XMPPInterface"
+ __type__ = "hook"
__version__ = "0.11"
- __type__ = "hook"
- __config__ = [("activated", "bool", "Activated", False),
- ("jid", "str", "Jabber ID", "user@exmaple-jabber-server.org"),
+ __config__ = [("jid", "str", "Jabber ID", "user@exmaple-jabber-server.org"),
("pw", "str", "Password", ""),
("tls", "bool", "Use TLS", False),
("owners", "str", "List of JIDs accepting commands from", "me@icq-gateway.org;some@msn-gateway.org"),
@@ -39,12 +23,13 @@ class XMPPInterface(IRCInterface, JabberClient):
("captcha", "bool", "Send captcha requests", True)]
__description__ = """Connect to jabber and let owner perform different tasks"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
implements(IMessageHandlersProvider)
+
def __init__(self, core, manager):
IRCInterface.__init__(self, core, manager)
@@ -73,11 +58,13 @@ class XMPPInterface(IRCInterface, JabberClient):
self,
]
+
def coreReady(self):
self.new_package = {}
self.start()
+
def packageFinished(self, pypack):
try:
if self.getConfig("info_pack"):
@@ -85,6 +72,7 @@ class XMPPInterface(IRCInterface, JabberClient):
except:
pass
+
def downloadFinished(self, pyfile):
try:
if self.getConfig("info_file"):
@@ -93,28 +81,34 @@ class XMPPInterface(IRCInterface, JabberClient):
except:
pass
+
def run(self):
# connect to IRC etc.
self.connect()
try:
self.loop()
except Exception, ex:
- self.logError("pyLoad XMPP: %s" % str(ex))
+ self.logError(ex)
+
def stream_state_changed(self, state, arg):
"""This one is called when the state of stream connecting the component
to a server changes. This will usually be used to let the user
know what is going on."""
- self.logDebug("pyLoad XMPP: *** State changed: %s %r ***" % (state, arg))
+ self.logDebug("*** State changed: %s %r ***" % (state, arg))
+
def disconnected(self):
- self.logDebug("pyLoad XMPP: Client was disconnected")
+ self.logDebug("Client was disconnected")
+
def stream_closed(self, stream):
- self.logDebug("pyLoad XMPP: Stream was closed | %s" % stream)
+ self.logDebug("Stream was closed", stream)
+
def stream_error(self, err):
- self.logDebug("pyLoad XMPP: Stream Error: %s" % err)
+ self.logDebug("Stream Error", err)
+
def get_message_handlers(self):
"""Return list of (message_type, message_handler) tuples.
@@ -123,13 +117,14 @@ class XMPPInterface(IRCInterface, JabberClient):
in a client session."""
return [("normal", self.message)]
+
def message(self, stanza):
"""Message handler for the component."""
subject = stanza.get_subject()
body = stanza.get_body()
t = stanza.get_type()
- self.logDebug(u'pyLoad XMPP: Message from %s received.' % (unicode(stanza.get_from(),)))
- self.logDebug(u'pyLoad XMPP: Body: %s Subject: %s Type: %s' % (body, subject, t))
+ self.logDebug("Message from %s received." % unicode(stanza.get_from()))
+ self.logDebug("Body: %s Subject: %s Type: %s" % (body, subject, t))
if t == "headline":
# 'headline' messages should never be replied to
@@ -173,20 +168,22 @@ class XMPPInterface(IRCInterface, JabberClient):
messages.append(m)
except Exception, e:
- self.logError("pyLoad XMPP: " + repr(e))
+ self.logError(e)
return messages
else:
return True
+
def response(self, msg, origin=""):
return self.announce(msg)
+
def announce(self, message):
""" send message to all owners"""
for user in self.getConfig("owners").split(";"):
- self.logDebug("pyLoad XMPP: Send message to %s" % user)
+ self.logDebug("Send message to", user)
to_jid = JID(user)
@@ -202,9 +199,11 @@ class XMPPInterface(IRCInterface, JabberClient):
stream.send(m)
+
def beforeReconnecting(self, ip):
self.disconnect()
+
def afterReconnecting(self, ip):
self.connect()
@@ -217,24 +216,29 @@ class VersionHandler(object):
implements(IIqHandlersProvider, IFeaturesProvider)
+
def __init__(self, client):
"""Just remember who created this."""
self.client = client
+
def get_features(self):
"""Return namespace which should the client include in its reply to a
disco#info query."""
return ["jabber:iq:version"]
+
def get_iq_get_handlers(self):
"""Return list of tuples (element_name, namespace, handler) describing
handlers of <iq type='get'/> stanzas"""
return [("query", "jabber:iq:version", self.get_version)]
+
def get_iq_set_handlers(self):
"""Return empty list, as this class provides no <iq type='set'/> stanza handler."""
return []
+
def get_version(self, iq):
"""Handler for jabber:iq:version queries.
diff --git a/module/plugins/hooks/ZeveraCom.py b/module/plugins/hooks/ZeveraCom.py
index 49fc68b30..6ca696f38 100644
--- a/module/plugins/hooks/ZeveraCom.py
+++ b/module/plugins/hooks/ZeveraCom.py
@@ -1,23 +1,22 @@
# -*- coding: utf-8 -*-
from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
+from module.plugins.internal.MultiHook import MultiHook
-class ZeveraCom(MultiHoster):
- __name__ = "ZeveraCom"
- __version__ = "0.02"
- __type__ = "hook"
+class ZeveraCom(MultiHook):
+ __name__ = "ZeveraCom"
+ __type__ = "hook"
+ __version__ = "0.03"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ __config__ = [("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
("hosterList", "str", "Hoster list (comma separated)", "")]
__description__ = """Real-Debrid.com hook plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
def getHoster(self):
- page = getURL("http://www.zevera.com/jDownloader.ashx?cmd=gethosters")
+ page = getURL("http://www.zevera.com/jDownloader.ashx", get={'cmd': "gethosters"})
return [x.strip() for x in page.replace("\"", "").split(",")]
diff --git a/module/plugins/hoster/AlldebridCom.py b/module/plugins/hoster/AlldebridCom.py
index b2064f22f..48dde3ce5 100644
--- a/module/plugins/hoster/AlldebridCom.py
+++ b/module/plugins/hoster/AlldebridCom.py
@@ -1,83 +1,82 @@
# -*- coding: utf-8 -*-
import re
-from urllib import unquote
+
from random import randrange
-from module.plugins.Hoster import Hoster
+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(Hoster):
- __name__ = "AlldebridCom"
- __version__ = "0.34"
- __type__ = "hoster"
+class AlldebridCom(MultiHoster):
+ __name__ = "AlldebridCom"
+ __type__ = "hoster"
+ __version__ = "0.41"
+
+ __pattern__ = r'https?://s\d+\.alldebrid\.com/dl/[\w^_]+'
- __pattern__ = r'https?://(?:[^/]*\.)?alldebrid\..*'
__description__ = """Alldebrid.com hoster plugin"""
- __author_name__ = "Andy Voigt"
- __author_mail__ = "spamsales@online.de"
+ __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
+ self.chunkLimit = 16
self.resumeDownload = True
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "AllDebrid")
- self.fail("No AllDebrid account provided")
- else:
- self.logDebug("Old URL: %s" % pyfile.url)
- password = self.getPassword().splitlines()
- password = "" if not password else password[0]
-
- url = "http://www.alldebrid.com/service.php?link=%s&json=true&pw=%s" % (pyfile.url, password)
- page = self.load(url)
- data = json_loads(page)
-
- self.logDebug("Json data: %s" % str(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()
+
+ def handlePremium(self):
+ password = self.getPassword()
+
+ data = json_loads(self.load("http://www.alldebrid.com/service.php",
+ get={'link': self.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:
- if pyfile.name and not pyfile.name.endswith('.tmp'):
- pyfile.name = data['filename']
- pyfile.size = parseFileSize(data['filesize'])
- new_url = data['link']
+ self.logWarning(data['error'])
+ self.tempOffline()
+ else:
+ if self.pyfile.name and not self.pyfile.name.endswith('.tmp'):
+ self.pyfile.name = data['filename']
+ self.pyfile.size = parseFileSize(data['filesize'])
+ self.link = data['link']
if self.getConfig("https"):
- new_url = new_url.replace("http://", "https://")
+ self.link = self.link.replace("http://", "https://")
else:
- new_url = new_url.replace("https://", "http://")
+ self.link = self.link.replace("https://", "http://")
- if new_url != pyfile.url:
- self.logDebug("New URL: %s" % new_url)
+ if self.link != self.pyfile.url:
+ self.logDebug("New URL: %s" % self.link)
- if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"):
+ if self.pyfile.name.startswith("http") or self.pyfile.name.startswith("Unknown"):
#only use when name wasnt already set
- pyfile.name = self.getFilename(new_url)
+ self.pyfile.name = self.getFilename(self.link)
+
+
+ def checkFile(self):
+ super(AlldebridCom, self).checkFile()
- self.download(new_url, disposition=True)
+ if self.checkDownload({'error': "<title>An error occured while processing your request</title>"}) is "error":
+ self.retry(wait_time=60, reason=_("An error occured while generating link"))
- check = self.checkDownload({"error": "<title>An error occured while processing your request</title>",
- "empty": re.compile(r"^$")})
- if check == "error":
- self.retry(wait_time=60, reason="An error occured while generating link.")
- elif check == "empty":
- self.retry(wait_time=60, reason="Downloaded File was empty.")
+getInfo = create_getInfo(AlldebridCom)
diff --git a/module/plugins/hoster/BasePlugin.py b/module/plugins/hoster/BasePlugin.py
index 9206aaabd..d0d8e7cc8 100644
--- a/module/plugins/hoster/BasePlugin.py
+++ b/module/plugins/hoster/BasePlugin.py
@@ -1,114 +1,108 @@
# -*- coding: utf-8 -*-
-from urlparse import urlparse
-from re import match, search
+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
from module.plugins.Hoster import Hoster
-from module.utils import html_unescape, remove_chars
class BasePlugin(Hoster):
- __name__ = "BasePlugin"
- __type__ = "hoster"
+ __name__ = "BasePlugin"
+ __type__ = "hoster"
+ __version__ = "0.26"
+
__pattern__ = r'^unmatchable$'
- __version__ = "0.19"
+
__description__ = """Base Plugin when any other didnt fit"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __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
+ return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3 if url else 1, 'url': unquote(url) or ""}
def setup(self):
self.chunkLimit = -1
self.resumeDownload = True
+
def process(self, pyfile):
"""main function"""
- #debug part, for api exerciser
- if pyfile.url.startswith("DEBUG_API"):
- self.multiDL = False
- return
-
- # self.__name__ = "NetloadIn"
- # pyfile.name = "test"
- # self.html = self.load("http://localhost:9000/short")
- # self.download("http://localhost:9000/short")
- # self.api = self.load("http://localhost:9000/short")
- # self.decryptCaptcha("http://localhost:9000/captcha")
- #
- # if pyfile.url == "79":
- # self.core.api.addPackage("test", [str(i) for i in xrange(80)], 1)
- #
- # return
- if pyfile.url.startswith("http"):
+ pyfile.name = self.getInfo(pyfile.url)['name']
+ if not pyfile.url.startswith("http"):
+ self.fail(_("No plugin matched"))
+
+ for _i in xrange(5):
try:
self.downloadFile(pyfile)
+
except BadHeader, e:
- if e.code in (401, 403):
- self.logDebug("Auth required")
+ 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
+ server = urlparse(pyfile.url).netloc
if server in servers:
self.logDebug("Logging on to %s" % server)
self.req.addAuth(account.accounts[server]['password'])
else:
- for pwd in pyfile.package().password.splitlines():
- if ":" in pwd:
- self.req.addAuth(pwd.strip())
- break
+ pwd = self.getPassword()
+ if ':' in pwd:
+ self.req.addAuth(pwd)
else:
- self.fail(_("Authorization required (username:password)"))
-
- self.downloadFile(pyfile)
+ self.fail(_("Authorization required"))
else:
- raise
-
+ self.fail(e)
+ else:
+ break
else:
- self.fail("No Plugin matched and not a downloadable url.")
+ self.fail(_("No file downloaded")) #@TODO: Move to hoster class in 0.4.10
+
+ if self.checkDownload({'empty': re.compile(r"^$")}) is "empty": #@TODO: Move to hoster in 0.4.10
+ self.fail(_("Empty file"))
+
def downloadFile(self, pyfile):
url = pyfile.url
- for _ in xrange(5):
- header = self.load(url, just_header=True)
+ for i in xrange(1, 7): #@TODO: retrieve the pycurl.MAXREDIRS value set by req
+ header = self.load(url, ref=True, cookies=True, just_header=True, decode=True)
- # self.load does not raise a BadHeader on 404 responses, do it here
- if 'code' in header and header['code'] == 404:
- raise BadHeader(404)
-
- if 'location' in header:
- self.logDebug("Location: " + header['location'])
- base = match(r'https?://[^/]+', url).group(0)
- if header['location'].startswith("http"):
- url = unquote(header['location'])
- elif header['location'].startswith("/"):
- url = base + unquote(header['location'])
+ if 'location' not in header or not header['location']:
+ if 'code' in header and header['code'] not in (200, 201, 203, 206):
+ self.logDebug("Received HTTP status code: %d" % header['code'])
+ self.fail(_("File not found"))
else:
- url = '%s/%s' % (base, unquote(header['location']))
+ break
+
+ location = header['location']
+
+ self.logDebug("Redirect #%d to: %s" % (i, location))
+
+ if urlparse(location).scheme:
+ url = location
else:
- break
+ p = urlparse(url)
+ base = "%s://%s" % (p.scheme, p.netloc)
+ url = urljoin(base, location)
+ else:
+ self.fail(_("Too many redirects"))
+
+ self.download(unquote(url), disposition=True)
+
- name = html_unescape(unquote(urlparse(url).path.split("/")[-1]))
-
- if 'content-disposition' in header:
- self.logDebug("Content-Disposition: " + header['content-disposition'])
- m = search("filename(?P<type>=|\*=(?P<enc>.+)'')(?P<name>.*)", header['content-disposition'])
- if m:
- disp = m.groupdict()
- self.logDebug(disp)
- if not disp['enc']:
- disp['enc'] = 'utf-8'
- name = remove_chars(disp['name'], "\"';").strip()
- name = unicode(unquote(name), disp['enc'])
-
- if not name:
- name = url
- pyfile.name = name
- self.logDebug("Filename: %s" % pyfile.name)
- self.download(url, disposition=True)
+getInfo = create_getInfo(BasePlugin)
diff --git a/module/plugins/hoster/BayfilesCom.py b/module/plugins/hoster/BayfilesCom.py
index 272c7cd88..0929ece01 100644
--- a/module/plugins/hoster/BayfilesCom.py
+++ b/module/plugins/hoster/BayfilesCom.py
@@ -1,95 +1,18 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+class BayfilesCom(DeadHoster):
+ __name__ = "BayfilesCom"
+ __type__ = "hoster"
+ __version__ = "0.09"
-import re
-from time import time
+ __pattern__ = r'https?://(?:www\.)?bayfiles\.(com|net)/file/(?P<ID>\w+/\w+/[^/]+)'
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-from module.common.json_layer import json_loads
-
-
-class BayfilesCom(SimpleHoster):
- __name__ = "BayfilesCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?bayfiles\.(com|net)/file/(?P<ID>[a-zA-Z0-9]+/[a-zA-Z0-9]+/[^/]+)'
- __version__ = "0.07"
__description__ = """Bayfiles.com hoster plugin"""
- __author_name__ = ("zoidberg", "Walter Purcaro")
- __author_mail__ = ("zoidberg@mujmail.cz", "vuolter@gmail.com")
-
- FILE_INFO_PATTERN = r'<p title="(?P<N>[^"]+)">[^<]*<strong>(?P<S>[0-9., ]+)(?P<U>[kKMG])i?B</strong></p>'
- OFFLINE_PATTERN = r'(<p>The requested file could not be found.</p>|<title>404 Not Found</title>)'
-
- WAIT_PATTERN = r'>Your IP [0-9.]* has recently downloaded a file\. Upgrade to premium or wait (\d+) minutes\.<'
- VARS_PATTERN = r'var vfid = (\d+);\s*var delay = (\d+);'
- FREE_LINK_PATTERN = r"javascript:window.location.href = '([^']+)';"
- PREMIUM_LINK_PATTERN = r'(?:<a class="highlighted-btn" href="|(?=http://s\d+\.baycdn\.com/dl/))(.*?)"'
-
- def handleFree(self):
- m = re.search(self.WAIT_PATTERN, self.html)
- if m:
- self.wait(int(m.group(1)) * 60)
- self.retry()
-
- # Get download token
- m = re.search(self.VARS_PATTERN, self.html)
- if m is None:
- self.parseError('VARS')
- vfid, delay = m.groups()
-
- response = json_loads(self.load('http://bayfiles.com/ajax_download', get={
- "_": time() * 1000,
- "action": "startTimer",
- "vfid": vfid}, decode=True))
-
- if not "token" in response or not response['token']:
- self.fail('No token')
-
- self.wait(int(delay))
-
- self.html = self.load('http://bayfiles.com/ajax_download', get={
- "token": response['token'],
- "action": "getLink",
- "vfid": vfid})
-
- # Get final link and download
- m = re.search(self.FREE_LINK_PATTERN, self.html)
- if m is None:
- self.parseError("Free link")
- self.startDownload(m.group(1))
-
- def handlePremium(self):
- m = re.search(self.PREMIUM_LINK_PATTERN, self.html)
- if m is None:
- self.parseError("Premium link")
- self.startDownload(m.group(1))
-
- def startDownload(self, url):
- self.logDebug("%s URL: %s" % ("Premium" if self.premium else "Free", url))
- self.download(url)
- # check download
- check = self.checkDownload({
- "waitforfreeslots": re.compile(r"<title>BayFiles</title>"),
- "notfound": re.compile(r"<title>404 Not Found</title>")
- })
- if check == "waitforfreeslots":
- self.retry(30, 5 * 60, "Wait for free slot")
- elif check == "notfound":
- self.retry(30, 5 * 60, "404 Not found")
+ __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
index a6336ad19..9ca4b4b1a 100644
--- a/module/plugins/hoster/BezvadataCz.py
+++ b/module/plugins/hoster/BezvadataCz.py
@@ -1,58 +1,50 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class BezvadataCz(SimpleHoster):
- __name__ = "BezvadataCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?bezvadata.cz/stahnout/.*'
- __version__ = "0.24"
+ __name__ = "BezvadataCz"
+ __type__ = "hoster"
+ __version__ = "0.25"
+
+ __pattern__ = r'http://(?:www\.)?bezvadata\.cz/stahnout/.+'
+
__description__ = """BezvaData.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<p><b>Soubor: (?P<N>[^<]+)</b></p>'
- FILE_SIZE_PATTERN = r'<li><strong>Velikost:</strong> (?P<S>[^<]+)</li>'
+
+ 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.multiDL = self.resumeDownload = True
+ self.resumeDownload = True
+ self.multiDL = True
+
def handleFree(self):
#download button
m = re.search(r'<a class="stahnoutSoubor".*?href="(.*?)"', self.html)
if m is None:
- self.parseError("page1 URL")
+ 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 _ in xrange(5):
+ for _i in xrange(5):
action, inputs = self.parseHtmlForm('frm-stahnoutFreeForm')
if not inputs:
- self.parseError("FreeForm")
+ self.error(_("FreeForm"))
m = re.search(r'<img src="data:image/png;base64,(.*?)"', self.html)
if m is None:
- self.parseError("captcha img")
+ 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
@@ -67,30 +59,34 @@ class BezvadataCz(SimpleHoster):
self.correctCaptcha()
break
else:
- self.fail("No valid captcha code entered")
+ 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.parseError("page2 URL")
+ 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)) + 1) if m else 120
+ 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
+ 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/module/plugins/hoster/BillionuploadsCom.py b/module/plugins/hoster/BillionuploadsCom.py
index ab2634c91..b20ace0f1 100644
--- a/module/plugins/hoster/BillionuploadsCom.py
+++ b/module/plugins/hoster/BillionuploadsCom.py
@@ -1,21 +1,24 @@
# -*- coding: utf-8 -*-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class BillionuploadsCom(XFileSharingPro):
- __name__ = "BillionuploadsCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?billionuploads.com/\w{12}'
- __version__ = "0.01"
+class BillionuploadsCom(XFSHoster):
+ __name__ = "BillionuploadsCom"
+ __type__ = "hoster"
+ __version__ = "0.04"
+
+ __pattern__ = r'http://(?:www\.)?billionuploads\.com/\w{12}'
+
__description__ = """Billionuploads.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- HOSTER_NAME = "billionuploads.com"
+ HOSTER_DOMAIN = "billionuploads.com"
- FILE_NAME_PATTERN = r'<b>Filename:</b>(?P<N>.*?)<br>'
- FILE_SIZE_PATTERN = r'<b>Size:</b>(?P<S>.*?)<br>'
+ 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
index a6ed51d94..1c5c53f55 100644
--- a/module/plugins/hoster/BitshareCom.py
+++ b/module/plugins/hoster/BitshareCom.py
@@ -9,38 +9,39 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class BitshareCom(SimpleHoster):
- __name__ = "BitshareCom"
- __version__ = "0.50"
- __type__ = "hoster"
+ __name__ = "BitshareCom"
+ __type__ = "hoster"
+ __version__ = "0.51"
- __pattern__ = r'http://(?:www\.)?bitshare\.com/(files/(?P<id1>[a-zA-Z0-9]+)(/(?P<name>.*?)\.html)?|\?f=(?P<id2>[a-zA-Z0-9]+))'
+ __pattern__ = r'http://(?:www\.)?bitshare\.com/(files/)?(?(1)|\?f=)(?P<ID>\w+)(?(1)/(?P<NAME>.+?)\.html)'
__description__ = """Bitshare.com hoster plugin"""
- __author_name__ = ("Paul King", "fragonib")
- __author_mail__ = ("", "fragonib[AT]yahoo[DOT]es")
+ __license__ = "GPLv3"
+ __authors__ = [("Paul King", None),
+ ("fragonib", "fragonib[AT]yahoo[DOT]es")]
- FILE_INFO_PATTERN = r'Downloading (?P<N>.+) - (?P<S>[\d.]+) (?P<U>\w+)</h1>'
- OFFLINE_PATTERN = r'(>We are sorry, but the requested file was not found in our database|>Error - File not available<|The file was deleted either by the uploader, inactivity or due to copyright claim)'
- FILE_AJAXID_PATTERN = r'var ajaxdl = "(.*?)";'
- CAPTCHA_KEY_PATTERN = r'http://api\.recaptcha\.net/challenge\?k=(.*?) '
- TRAFFIC_USED_UP = r'Your Traffic is used up for today. Upgrade to premium to continue!'
+ 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.req.cj.setCookie(".bitshare.com", "language_selection", "EN")
- self.multiDL = self.premium
+ self.multiDL = self.premium
self.chunkLimit = 1
+
def process(self, pyfile):
if self.premium:
self.account.relogin(self.user)
- self.pyfile = pyfile
-
# File id
m = re.match(self.__pattern__, pyfile.url)
- self.file_id = max(m.group('id1'), m.group('id2'))
+ self.file_id = max(m.group('ID1'), m.group('ID2'))
self.logDebug("File id is [%s]" % self.file_id)
# Load main page
@@ -52,32 +53,35 @@ class BitshareCom(SimpleHoster):
# Check Traffic used up
if re.search(self.TRAFFIC_USED_UP, self.html):
- self.logInfo("Your Traffic is used up for today")
+ 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.FILE_INFO_PATTERN, self.html)
+ 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.FILE_AJAXID_PATTERN, self.html).group(1)
+ 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
- url = self.getDownloadUrl()
- self.logDebug("Downloading file with url [%s]" % url)
- self.download(url)
+ self.download(self.getDownloadUrl())
check = self.checkDownload({"404": ">404 Not Found<", "Error": ">Error occured<"})
+
if check == "404":
self.retry(3, 60, 'Error 404')
+
elif check == "error":
self.retry(5, 5 * 60, "Bitshare host : Error occured")
+
def getDownloadUrl(self):
# Return location if direct download is active
if self.premium:
@@ -87,13 +91,16 @@ class BitshareCom(SimpleHoster):
# Get download info
self.logDebug("Getting download info")
- response = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html",
- post={"request": "generateID", "ajaxid": self.ajaxid})
- self.handleErrors(response, ':')
- parts = response.split(":")
+ 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])
+ wait = int(parts[1])
+ captcha = int(parts[2])
+
self.logDebug("Download info [type: '%s', waiting: %d, captcha: %d]" % (filetype, wait, captcha))
# Waiting
@@ -108,43 +115,48 @@ class BitshareCom(SimpleHoster):
# Resolve captcha
if captcha == 1:
self.logDebug("File is captcha protected")
- id = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group(1)
+ recaptcha = ReCaptcha(self)
+
# Try up to 3 times
for i in xrange(3):
- self.logDebug("Resolving ReCaptcha with key [%s], round %d" % (id, i + 1))
- recaptcha = ReCaptcha(self)
- challenge, code = recaptcha.challenge(id)
- response = 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": code})
- if self.handleCaptchaErrors(response):
+ challenge, response = 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")
- response = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html",
- post={"request": "getDownloadURL", "ajaxid": self.ajaxid})
- self.handleErrors(response, '#')
- url = response.split("#")[-1]
+ 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, response, separator):
- self.logDebug("Checking response [%s]" % response)
- if "ERROR:Session timed out" in response:
+
+ def handleErrors(self, res, separator):
+ self.logDebug("Checking response [%s]" % res)
+ if "ERROR:Session timed out" in res:
self.retry()
- elif "ERROR" in response:
- msg = response.split(separator)[-1]
+ elif "ERROR" in res:
+ msg = res.split(separator)[-1]
self.fail(msg)
- def handleCaptchaErrors(self, response):
- self.logDebug("Result of captcha resolving [%s]" % response)
- if "SUCCESS" in response:
+
+ 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 response:
+ elif "ERROR:SESSION ERROR" in res:
self.retry()
- self.logDebug("Wrong captcha")
+
self.invalidCaptcha()
diff --git a/module/plugins/hoster/BoltsharingCom.py b/module/plugins/hoster/BoltsharingCom.py
index a1672dc22..924545a29 100644
--- a/module/plugins/hoster/BoltsharingCom.py
+++ b/module/plugins/hoster/BoltsharingCom.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class BoltsharingCom(DeadHoster):
- __name__ = "BoltsharingCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?boltsharing.com/\w{12}'
+ __name__ = "BoltsharingCom"
+ __type__ = "hoster"
__version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?boltsharing\.com/\w{12}'
+
__description__ = """Boltsharing.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
index 2cd85420d..949a021dd 100644
--- a/module/plugins/hoster/CatShareNet.py
+++ b/module/plugins/hoster/CatShareNet.py
@@ -1,41 +1,67 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
from module.plugins.internal.CaptchaService import ReCaptcha
class CatShareNet(SimpleHoster):
- __name__ = "CatShareNet"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?catshare.net/\w{16}.*'
- __version__ = "0.01"
+ __name__ = "CatShareNet"
+ __type__ = "hoster"
+ __version__ = "0.08"
+
+ __pattern__ = r'http://(?:www\.)?catshare\.net/\w{16}'
+
__description__ = """CatShare.net hoster plugin"""
- __author_name__ = "z00nx"
- __author_mail__ = "z00nx0@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("z00nx", "z00nx0@gmail.com"),
+ ("prOq", None),
+ ("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>'
- FILE_INFO_PATTERN = r'<h3 class="pull-left"[^>]+>(?P<N>.*)</h3>\s+<h3 class="pull-right"[^>]+>(?P<S>.*)</h3>'
- OFFLINE_PATTERN = r'Podany plik zosta'
+ IP_BLOCKED_PATTERN = ur'>Nasz serwis wykrył ÅŒe Twój adres IP nie pochodzi z Polski.<'
+ SECONDS_PATTERN = 'var\scount\s=\s(\d+);'
+ LINK_PATTERN = r'<form action="(.+?)" method="GET">'
- SECONDS_PATTERN = r'var\s+count\s+=\s+(\d+);'
- RECAPTCHA_KEY = "6Lfln9kSAAAAANZ9JtHSOgxUPB9qfDFeLUI_QMEy"
+ 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):
m = re.search(self.SECONDS_PATTERN, self.html)
- seconds = int(m.group(1))
- self.logDebug("Seconds found", seconds)
- self.wait(seconds + 1)
+ if m:
+ wait_time = int(m.group(1))
+ self.wait(wait_time, True)
+
recaptcha = ReCaptcha(self)
- challenge, code = recaptcha.challenge(self.RECAPTCHA_KEY)
- post_data = {"recaptcha_challenge_field": challenge, "recaptcha_response_field": code}
- self.download(self.pyfile.url, post=post_data)
- check = self.checkDownload({"html": re.compile("\A<!DOCTYPE html PUBLIC")})
- if check == "html":
- self.logDebug("Wrong captcha entered")
+
+ challenge, response = recaptcha.challenge()
+ self.html = self.load(self.pyfile.url,
+ post={'recaptcha_challenge_field': challenge,
+ 'recaptcha_response_field' : response})
+
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
self.invalidCaptcha()
- self.retry()
+ self.retry(reason=_("Wrong captcha entered"))
+
+ dl_link = m.group(1)
+ self.download(dl_link, disposition=True)
getInfo = create_getInfo(CatShareNet)
diff --git a/module/plugins/hoster/CloudzerNet.py b/module/plugins/hoster/CloudzerNet.py
index 6e47ce53f..c5440391f 100644
--- a/module/plugins/hoster/CloudzerNet.py
+++ b/module/plugins/hoster/CloudzerNet.py
@@ -4,13 +4,17 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class CloudzerNet(DeadHoster):
- __name__ = "CloudzerNet"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?(cloudzer\.net/file/|clz\.to/(file/)?)\w+'
+ __name__ = "CloudzerNet"
+ __type__ = "hoster"
__version__ = "0.05"
+
+ __pattern__ = r'https?://(?:www\.)?(cloudzer\.net/file/|clz\.to/(file/)?)\w+'
+
__description__ = """Cloudzer.net hoster plugin"""
- __author_name__ = ("gs", "z00nx", "stickell")
- __author_mail__ = ("I-_-I-_-I@web.de", "z00nx0@gmail.com", "l.stickell@yahoo.it")
+ __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
new file mode 100644
index 000000000..d8b5e8b5d
--- /dev/null
+++ b/module/plugins/hoster/CloudzillaTo.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class CloudzillaTo(SimpleHoster):
+ __name__ = "CloudzillaTo"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __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):
+ 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(int(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):
+ return self.handleFree()
+
+
+getInfo = create_getInfo(CloudzillaTo)
diff --git a/module/plugins/hoster/CramitIn.py b/module/plugins/hoster/CramitIn.py
index 79ed07e73..f444718bc 100644
--- a/module/plugins/hoster/CramitIn.py
+++ b/module/plugins/hoster/CramitIn.py
@@ -1,24 +1,25 @@
# -*- coding: utf-8 -*-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class CramitIn(XFileSharingPro):
- __name__ = "CramitIn"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?cramit.in/\w{12}'
- __version__ = "0.04"
+class CramitIn(XFSHoster):
+ __name__ = "CramitIn"
+ __type__ = "hoster"
+ __version__ = "0.07"
+
+ __pattern__ = r'http://(?:www\.)?cramit\.in/\w{12}'
+
__description__ = """Cramit.in hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- HOSTER_NAME = "cramit.in"
+ HOSTER_DOMAIN = "cramit.in"
- FILE_INFO_PATTERN = r'<span class=t2>\s*(?P<N>.*?)</span>.*?<small>\s*\((?P<S>.*?)\)'
- LINK_PATTERN = r'href="(http://cramit.in/file_download/.*?)"'
+ INFO_PATTERN = r'<span class=t2>\s*(?P<N>.*?)</span>.*?<small>\s*\((?P<S>.*?)\)'
- def setup(self):
- self.resumeDownload = self.multiDL = self.premium
+ 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
index b36d59993..e5f94800b 100644
--- a/module/plugins/hoster/CrockoCom.py
+++ b/module/plugins/hoster/CrockoCom.py
@@ -2,64 +2,61 @@
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class CrockoCom(SimpleHoster):
- __name__ = "CrockoCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(crocko|easy-share).com/\w+'
- __version__ = "0.16"
+ __name__ = "CrockoCom"
+ __type__ = "hoster"
+ __version__ = "0.17"
+
+ __pattern__ = r'http://(?:www\.)?(crocko|easy-share)\.com/\w+'
+
__description__ = """Crocko hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<span class="fz24">Download:\s*<strong>(?P<N>.*)'
- FILE_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_URL_PATTERN = re.compile(r"u='(/file_contents/captcha/\w+)';\s*w='(\d+)';")
- CAPTCHA_KEY_PATTERN = re.compile(r'Recaptcha.create\("([^"]+)"')
+ 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="?([^" ]+)"?[^>]*>'
- FILE_NAME_REPLACEMENTS = [(r'<[^>]*>', '')]
+ NAME_REPLACEMENTS = [(r'<[^>]*>', '')]
def handleFree(self):
if "You need Premium membership to download this file." in self.html:
- self.fail("You need Premium membership to download this file.")
+ self.fail(_("You need Premium membership to download this file"))
- for _ in xrange(5):
- m = re.search(self.CAPTCHA_URL_PATTERN, self.html)
+ for _i in xrange(5):
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
if m:
- url, wait_time = 'http://crocko.com' + m.group(1), m.group(2)
+ 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.CAPTCHA_KEY_PATTERN, self.html)
+ m = re.search(self.FORM_PATTERN, self.html, re.S)
if m is None:
- self.parseError('Captcha KEY')
- captcha_key = m.group(1)
+ self.error(_("FORM_PATTERN not found"))
- m = re.search(self.FORM_PATTERN, self.html, re.DOTALL)
- if m is None:
- self.parseError('ACTION')
action, form = m.groups()
inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form))
-
recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(captcha_key)
+ for _i in xrange(5):
+ inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge()
self.download(action, post=inputs)
check = self.checkDownload({
- "captcha_err": self.CAPTCHA_KEY_PATTERN
+ "captcha_err": recaptcha.KEY_AJAX_PATTERN
})
if check == "captcha_err":
@@ -67,7 +64,7 @@ class CrockoCom(SimpleHoster):
else:
break
else:
- self.fail('No valid captcha solution received')
+ 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
index a08bf8518..b26909096 100644
--- a/module/plugins/hoster/CyberlockerCh.py
+++ b/module/plugins/hoster/CyberlockerCh.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class CyberlockerCh(DeadHoster):
- __name__ = "CyberlockerCh"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?cyberlocker\.ch/\w+'
+ __name__ = "CyberlockerCh"
+ __type__ = "hoster"
__version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?cyberlocker\.ch/\w+'
+
__description__ = """Cyberlocker.ch hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __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
index c34e73ff4..aa381d712 100644
--- a/module/plugins/hoster/CzshareCom.py
+++ b/module/plugins/hoster/CzshareCom.py
@@ -1,52 +1,41 @@
# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-# Test links (random.bin):
+#
+# Test links:
# http://czshare.com/5278880/random.bin
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
from module.utils import parseFileSize
class CzshareCom(SimpleHoster):
- __name__ = "CzshareCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(czshare|sdilej)\.(com|cz)/(\d+/|download.php\?).*'
- __version__ = "0.94"
+ __name__ = "CzshareCom"
+ __type__ = "hoster"
+ __version__ = "0.96"
+
+ __pattern__ = r'http://(?:www\.)?(czshare|sdilej)\.(com|cz)/(\d+/|download\.php\?).+'
+
__description__ = """CZshare.com hoster plugin, now Sdilej.cz"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<div class="tab" id="parameters">\s*<p>\s*Cel. n.zev: <a href=[^>]*>(?P<N>[^<]+)</a>'
- FILE_SIZE_PATTERN = r'<div class="tab" id="category">(?:\s*<p>[^\n]*</p>)*\s*Velikost:\s*(?P<S>[0-9., ]+)(?P<U>[kKMG])i?B\s*</div>'
+
+ 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">'
- FILE_SIZE_REPLACEMENTS = [(' ', '')]
- FILE_URL_REPLACEMENTS = [(r'http://[^/]*/download.php\?.*?id=(\w+).*', r'http://sdilej.cz/\1/x/')]
+ SIZE_REPLACEMENTS = [(' ', '')]
+ URL_REPLACEMENTS = [(r'http://[^/]*/download.php\?.*?id=(\w+).*', r'http://sdilej.cz/\1/x/')]
- SH_CHECK_TRAFFIC = True
+ 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>([0-9., ]+)([kKMG]i?B)</strong>\s*</div><!-- .credit -->'
+ 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):
@@ -62,35 +51,37 @@ class CzshareCom(SimpleHoster):
# 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))
+ 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)
+ 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('Parse error (CREDIT): %s' % e)
+ self.logError(e)
return True
+
def handlePremium(self):
# parse download link
try:
- form = re.search(self.PREMIUM_FORM_PATTERN, self.html, re.DOTALL).group(1)
+ 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("Parse error (FORM): %s" % 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)
self.checkDownloadedFile()
+
def handleFree(self):
# get free url
m = re.search(self.FREE_URL_PATTERN, self.html)
if m is None:
- self.parseError('Free URL')
+ self.error(_("FREE_URL_PATTERN not found"))
parsed_url = "http://sdilej.cz" + m.group(1)
self.logDebug("PARSED_URL:" + parsed_url)
@@ -100,16 +91,16 @@ class CzshareCom(SimpleHoster):
self.longWait(5 * 60, 12)
try:
- form = re.search(self.FREE_FORM_PATTERN, self.html, re.DOTALL).group(1)
+ form = re.search(self.FREE_FORM_PATTERN, self.html, re.S).group(1)
inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form))
self.pyfile.size = int(inputs['size'])
except Exception, e:
self.logError(e)
- self.parseError('Form')
+ self.error(_("Form"))
- # get and decrypt captcha
+ # get and decrypt captcha
captcha_url = 'http://sdilej.cz/captcha.php'
- for _ in xrange(5):
+ 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:
@@ -120,7 +111,7 @@ class CzshareCom(SimpleHoster):
self.correctCaptcha()
break
else:
- self.fail("No valid captcha code entered")
+ 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)
@@ -129,7 +120,7 @@ class CzshareCom(SimpleHoster):
self.logDebug("WAIT URL", self.req.lastEffectiveURL)
m = re.search("free_wait.php\?server=(.*?)&(.*)", self.req.lastEffectiveURL)
if m is None:
- self.parseError('Download URL')
+ self.error(_("Download URL not found"))
url = "http://%s/download.php?%s" % (m.group(1), m.group(2))
@@ -137,17 +128,18 @@ class CzshareCom(SimpleHoster):
self.download(url)
self.checkDownloadedFile()
+
def checkDownloadedFile(self):
# check download
check = self.checkDownload({
- "tempoffline": re.compile(r"^Soubor je do.*asn.* nedostupn.*$"),
+ "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_err": "<li>ZadanÃœ ověřovací kód nesouhlasí!</li>"
})
- if check == "tempoffline":
- self.fail("File not available - try later")
+ if check == "temp_offline":
+ self.fail(_("File not available - try later"))
if check == "credit":
self.resetAccount()
elif check == "multi_dl":
diff --git a/module/plugins/hoster/DailymotionCom.py b/module/plugins/hoster/DailymotionCom.py
index 5f032ca8b..dc42d1f60 100644
--- a/module/plugins/hoster/DailymotionCom.py
+++ b/module/plugins/hoster/DailymotionCom.py
@@ -1,42 +1,25 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-############################################################################
-
import re
+from module.PyFile import statusMap
from module.common.json_layer import json_loads
from module.network.RequestFactory import getURL
from module.plugins.Hoster import Hoster
-from module.PyFile import statusMap
def getInfo(urls):
- result = [] #: [ .. (name, size, status, url) .. ]
- regex = re.compile(DailymotionCom.__pattern__)
- apiurl = "https://api.dailymotion.com/video/"
+ result = []
+ regex = re.compile(DailymotionCom.__pattern__)
+ apiurl = "https://api.dailymotion.com/video/%s"
request = {"fields": "access_error,status,title"}
+
for url in urls:
- id = regex.search(url).group("ID")
- page = getURL(apiurl + id, get=request)
+ id = regex.match(url).group('ID')
+ page = getURL(apiurl % id, get=request)
info = json_loads(page)
- if "title" in info:
- name = info['title'] + ".mp4"
- else:
- name = url
+ name = info['title'] + ".mp4" if "title" in info else url
if "error" in info or info['access_error']:
status = "offline"
@@ -50,43 +33,57 @@ def getInfo(urls):
status = "offline"
result.append((name, 0, statusMap[status], url))
+
return result
class DailymotionCom(Hoster):
- __name__ = "DailymotionCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?dailymotion\.com/.*?video/(?P<ID>[\w^_]+)'
- __version__ = "0.2"
- __config__ = [("quality", "Lowest;LD 144p;LD 240p;SD 384p;HQ 480p;HD 720p;HD 1080p;Highest", "Quality", "Highest")]
+ __name__ = "DailymotionCom"
+ __type__ = "hoster"
+ __version__ = "0.20"
+
+ __pattern__ = r'https?://(?:www\.)?dailymotion\.com/.*video/(?P<ID>[\w^_]+)'
+ __config__ = [("quality", "Lowest;LD 144p;LD 240p;SD 384p;HQ 480p;HD 720p;HD 1080p;Highest", "Quality", "Highest")]
+
__description__ = """Dailymotion.com hoster plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
def setup(self):
- self.resumeDownload = self.multiDL = True
+ self.resumeDownload = True
+ self.multiDL = True
+
def getStreams(self):
streams = []
+
for result in re.finditer(r"\"(?P<URL>http:\\/\\/www.dailymotion.com\\/cdn\\/H264-(?P<QF>.*?)\\.*?)\"",
self.html):
- url = result.group("URL")
- qf = result.group("QF")
- link = url.replace("\\", "")
+ url = result.group('URL')
+ qf = result.group('QF')
+
+ link = url.replace("\\", "")
quality = tuple(int(x) for x in qf.split("x"))
+
streams.append((quality, link))
+
return sorted(streams, key=lambda x: x[0][::-1])
+
def getQuality(self):
q = self.getConfig("quality")
+
if q == "Lowest":
quality = 0
elif q == "Highest":
quality = -1
else:
quality = int(q.rsplit(" ")[1][:-1])
+
return quality
+
def getLink(self, streams, quality):
if quality > 0:
for x, s in reversed([item for item in enumerate(streams)]):
@@ -100,24 +97,29 @@ class DailymotionCom(Hoster):
idx = quality
s = streams[idx]
- self.logInfo("Download video quality %sx%s" % s[0])
+
+ self.logInfo(_("Download video quality %sx%s") % s[0])
+
return s[1]
+
def checkInfo(self, pyfile):
pyfile.name, pyfile.size, pyfile.status, pyfile.url = getInfo([pyfile.url])[0]
+
if pyfile.status == 1:
self.offline()
+
elif pyfile.status == 6:
self.tempOffline()
+
def process(self, pyfile):
self.checkInfo(pyfile)
- id = re.match(self.__pattern__, pyfile.url).group("ID")
+ id = re.match(self.__pattern__, pyfile.url).group('ID')
self.html = self.load("http://www.dailymotion.com/embed/video/" + id, decode=True)
streams = self.getStreams()
quality = self.getQuality()
- link = self.getLink(streams, quality)
- self.download(link)
+ self.download(self.getLink(streams, quality))
diff --git a/module/plugins/hoster/DataHu.py b/module/plugins/hoster/DataHu.py
index 9a7af288b..437fea7cd 100644
--- a/module/plugins/hoster/DataHu.py
+++ b/module/plugins/hoster/DataHu.py
@@ -1,20 +1,6 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-# Test links (random.bin):
+#
+# Test links:
# http://data.hu/get/6381232/random.bin
import re
@@ -23,30 +9,34 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class DataHu(SimpleHoster):
- __name__ = "DataHu"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?data.hu/get/\w+'
- __version__ = "0.01"
+ __name__ = "DataHu"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?data\.hu/get/\w+'
+
__description__ = """Data.hu hoster plugin"""
- __author_name__ = ("crash", "stickell")
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("crash", None),
+ ("stickell", "l.stickell@yahoo.it")]
- FILE_INFO_PATTERN = ur'<title>(?P<N>.*) \((?P<S>[^)]+)\) let\xf6lt\xe9se</title>'
+
+ INFO_PATTERN = ur'<title>(?P<N>.*) \((?P<S>[^)]+)\) let\xf6lt\xe9se</title>'
OFFLINE_PATTERN = ur'Az adott f\xe1jl nem l\xe9tezik'
LINK_PATTERN = r'<div class="download_box_button"><a href="([^"]+)">'
- def handleFree(self):
+
+ def setup(self):
self.resumeDownload = True
- self.html = self.load(self.pyfile.url, decode=True)
+ self.multiDL = self.premium
+
+ def handleFree(self):
m = re.search(self.LINK_PATTERN, self.html)
- if m:
- url = m.group(1)
- self.logDebug('Direct link: ' + url)
- else:
- self.parseError('Unable to get direct link')
+ if m is None:
+ self.error(_("LINK_PATTERN not found"))
- self.download(url, disposition=True)
+ self.download(m.group(1), disposition=True)
getInfo = create_getInfo(DataHu)
diff --git a/module/plugins/hoster/DataportCz.py b/module/plugins/hoster/DataportCz.py
index 19be45f44..8e74f5553 100644
--- a/module/plugins/hoster/DataportCz.py
+++ b/module/plugins/hoster/DataportCz.py
@@ -1,62 +1,48 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class DataportCz(SimpleHoster):
- __name__ = "DataportCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?dataport.cz/file/(.*)'
- __version__ = "0.37"
+ __name__ = "DataportCz"
+ __type__ = "hoster"
+ __version__ = "0.40"
+
+ __pattern__ = r'http://(?:www\.)?dataport\.cz/file/(.+)'
+
__description__ = """Dataport.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<span itemprop="name">(?P<N>[^<]+)</span>'
- FILE_SIZE_PATTERN = r'<td class="fil">Velikost</td>\s*<td>(?P<S>[^<]+)</td>'
- OFFLINE_PATTERN = r'<h2>Soubor nebyl nalezen</h2>'
- FILE_URL_REPLACEMENTS = [(__pattern__, r'http://www.dataport.cz/file/\1')]
+ 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_URL_PATTERN = r'<section id="captcha_bg">\s*<img src="(.*?)"'
+ 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):
captchas = {"1": "jkeG", "2": "hMJQ", "3": "vmEK", "4": "ePQM", "5": "blBd"}
- for _ in xrange(60):
+ for _i in xrange(60):
action, inputs = self.parseHtmlForm('free_download_form')
self.logDebug(action, inputs)
if not action or not inputs:
- self.parseError('free_download_form')
+ self.error(_("free_download_form"))
if "captchaId" in inputs and inputs['captchaId'] in captchas:
inputs['captchaCode'] = captchas[inputs['captchaId']]
else:
- self.parseError('captcha')
+ 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.parseError('invalid captcha')
+ self.error(_("invalid captcha"))
elif check == "slot":
self.logDebug("No free slots - wait 60s and retry")
self.wait(60, False)
@@ -66,4 +52,4 @@ class DataportCz(SimpleHoster):
break
-create_getInfo(DataportCz)
+getInfo = create_getInfo(DataportCz)
diff --git a/module/plugins/hoster/DateiTo.py b/module/plugins/hoster/DateiTo.py
index 4d39b178e..e4bff8458 100644
--- a/module/plugins/hoster/DateiTo.py
+++ b/module/plugins/hoster/DateiTo.py
@@ -1,50 +1,39 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class DateiTo(SimpleHoster):
- __name__ = "DateiTo"
- __type__ = "hoster"
+ __name__ = "DateiTo"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
__pattern__ = r'http://(?:www\.)?datei\.to/datei/(?P<ID>\w+)\.html'
- __version__ = "0.02"
+
__description__ = """Datei.to hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_NAME_PATTERN = r'Dateiname:</td>\s*<td colspan="2"><strong>(?P<N>.*?)</'
- FILE_SIZE_PATTERN = r'Dateigr&ouml;&szlig;e:</td>\s*<td colspan="2">(?P<S>.*?)</'
+ NAME_PATTERN = r'Dateiname:</td>\s*<td colspan="2"><strong>(?P<N>.*?)</'
+ SIZE_PATTERN = r'Dateigr&ouml;&szlig;e:</td>\s*<td colspan="2">(?P<S>.*?)</'
OFFLINE_PATTERN = r'>Datei wurde nicht gefunden<|>Bitte wÀhle deine Datei aus... <'
- PARALELL_PATTERN = r'>Du lÀdst bereits eine Datei herunter<'
- WAIT_PATTERN = r'countdown\({seconds: (\d+)'
+ WAIT_PATTERN = r'countdown\({seconds: (\d+)'
+ MULTIDL_PATTERN = r'>Du lÀdst bereits eine Datei herunter<'
+
DATA_PATTERN = r'url: "(.*?)", data: "(.*?)",'
- RECAPTCHA_KEY_PATTERN = r'Recaptcha.create\("(.*?)"'
+
def handleFree(self):
url = 'http://datei.to/ajax/download.php'
- data = {'P': 'I', 'ID': self.file_info['ID']}
-
+ data = {'P': 'I', 'ID': self.info['pattern']['ID']}
recaptcha = ReCaptcha(self)
- for _ in xrange(10):
+ for _i in xrange(10):
self.logDebug("URL", url, "POST", data)
self.html = self.load(url, post=data)
self.checkErrors()
@@ -58,37 +47,36 @@ class DateiTo(SimpleHoster):
m = re.search(self.DATA_PATTERN, self.html)
if m is None:
- self.parseError('data')
+ 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'):
- m = re.search(self.RECAPTCHA_KEY_PATTERN, self.html)
- recaptcha_key = m.group(1) if m else "6LdBbL8SAAAAAI0vKUo58XRwDd5Tu_Ze1DA7qTao"
-
- data['recaptcha_challenge_field'], data['recaptcha_response_field'] = recaptcha.challenge(recaptcha_key)
-
+ data['recaptcha_challenge_field'], data['recaptcha_response_field'] = recaptcha.challenge()
else:
- self.fail('Too bad...')
+ self.fail(_("Too bad..."))
+
+ self.download(self.html)
- download_url = self.html
- self.logDebug('Download URL', download_url)
- self.download(download_url)
def checkErrors(self):
- m = re.search(self.PARALELL_PATTERN, self.html)
+ 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
- self.wait(wait_time + 1, False)
- self.retry()
+
+ 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 + 1, False)
+ self.wait(wait_time, False)
getInfo = create_getInfo(DateiTo)
diff --git a/module/plugins/hoster/DdlstorageCom.py b/module/plugins/hoster/DdlstorageCom.py
index 9122b094a..a45ef27e9 100644
--- a/module/plugins/hoster/DdlstorageCom.py
+++ b/module/plugins/hoster/DdlstorageCom.py
@@ -1,89 +1,19 @@
# -*- coding: utf-8 -*-
-import re
-from hashlib import md5
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro
-from module.network.RequestFactory import getURL
-from module.plugins.Plugin import chunks
-from module.common.json_layer import json_loads
+class DdlstorageCom(DeadHoster):
+ __name__ = "DdlstorageCom"
+ __type__ = "hoster"
+ __version__ = "1.02"
-def getInfo(urls):
- # DDLStorage API Documentation:
- # http://www.ddlstorage.com/cgi-bin/api_req.cgi?req_type=doc
- ids = dict()
- for url in urls:
- m = re.search(DdlstorageCom.__pattern__, url)
- ids[m.group('ID')] = url
+ __pattern__ = r'https?://(?:www\.)?ddlstorage\.com/\w+'
- for chunk in chunks(ids.keys(), 5):
- for _ in xrange(5):
- api = getURL('http://www.ddlstorage.com/cgi-bin/api_req.cgi',
- post={'req_type': 'file_info_free',
- 'client_id': 53472,
- 'file_code': ','.join(chunk),
- 'sign': md5('file_info_free%d%s%s' % (53472, ','.join(chunk),
- '25JcpU2dPOKg8E2OEoRqMSRu068r0Cv3')).hexdigest()})
- api = api.replace('<pre>', '').replace('</pre>', '')
- api = json_loads(api)
- if 'error' not in api:
- break
-
- result = list()
- for el in api:
- if el['status'] == 'online':
- result.append((el['file_name'], int(el['file_size']), 2, ids[el['file_code']]))
- else:
- result.append((ids[el['file_code']], 0, 1, ids[el['file_code']]))
- yield result
-
-
-class DdlstorageCom(XFileSharingPro):
- __name__ = "DdlstorageCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?ddlstorage.com/(?P<ID>\w{12})'
- __version__ = "1.01"
__description__ = """DDLStorage.com hoster plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
-
- HOSTER_NAME = "ddlstorage.com"
-
- FILE_INFO_PATTERN = r'<p class="sub_title"[^>]*>(?P<N>.+) \((?P<S>[^)]+)\)</p>'
-
- def prepare(self):
- self.getAPIData()
- super(DdlstorageCom, self).prepare()
-
- def getAPIData(self):
- file_id = re.match(self.__pattern__, self.pyfile.url).group('ID')
- data = {'client_id': 53472,
- 'file_code': file_id}
- if self.user:
- passwd = self.account.getAccountData(self.user)['password']
- data['req_type'] = 'file_info_reg'
- data['user_login'] = self.user
- data['user_password'] = md5(passwd).hexdigest()
- data['sign'] = md5('file_info_reg%d%s%s%s%s' % (data['client_id'], data['user_login'],
- data['user_password'], data['file_code'],
- '25JcpU2dPOKg8E2OEoRqMSRu068r0Cv3')).hexdigest()
- else:
- data['req_type'] = 'file_info_free'
- data['sign'] = md5('file_info_free%d%s%s' % (data['client_id'], data['file_code'],
- '25JcpU2dPOKg8E2OEoRqMSRu068r0Cv3')).hexdigest()
-
- self.api_data = self.load('http://www.ddlstorage.com/cgi-bin/api_req.cgi', post=data)
- self.api_data = self.api_data.replace('<pre>', '').replace('</pre>', '')
- self.logDebug('API Data: ' + self.api_data)
- self.api_data = json_loads(self.api_data)[0]
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
- if self.api_data['status'] == 'offline':
- self.offline()
- if 'file_name' in self.api_data:
- self.pyfile.name = self.api_data['file_name']
- if 'file_size' in self.api_data:
- self.pyfile.size = self.api_data['size'] = self.api_data['file_size']
- if 'file_md5_base64' in self.api_data:
- self.api_data['md5_ddlstorage'] = self.api_data['file_md5_base64']
+getInfo = create_getInfo(DdlstorageCom)
diff --git a/module/plugins/hoster/DebridItaliaCom.py b/module/plugins/hoster/DebridItaliaCom.py
index a8b4248b4..34a306cce 100644
--- a/module/plugins/hoster/DebridItaliaCom.py
+++ b/module/plugins/hoster/DebridItaliaCom.py
@@ -1,60 +1,48 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
-from module.plugins.Hoster import Hoster
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
-class DebridItaliaCom(Hoster):
- __name__ = "DebridItaliaCom"
- __version__ = "0.05"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:[^/]*\.)?debriditalia\.com'
+class DebridItaliaCom(MultiHoster):
+ __name__ = "DebridItaliaCom"
+ __type__ = "hoster"
+ __version__ = "0.15"
+
+ __pattern__ = r'http://s\d+\.debriditalia\.com/dl/\d+'
+
__description__ = """Debriditalia.com hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ URL_REPLACEMENTS = [("https://", "http://")]
+
def setup(self):
- self.chunkLimit = -1
+ self.chunkLimit = 1
self.resumeDownload = True
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "DebridItalia")
- self.fail("No DebridItalia account provided")
- else:
- self.logDebug("Old URL: %s" % pyfile.url)
- url = "http://debriditalia.com/linkgen2.php?xjxfun=convertiLink&xjxargs[]=S<![CDATA[%s]]>" % pyfile.url
- page = self.load(url)
- self.logDebug("XML data: %s" % page)
- if 'File not available' in page:
- self.fail('File not available')
- else:
- new_url = re.search(r'<a href="(?:[^"]+)">(?P<direct>[^<]+)</a>', page).group('direct')
+ def handlePremium(self):
+ self.html = self.load("http://www.debriditalia.com/api.php",
+ get={'generate': "on", 'link': self.pyfile.url, 'p': self.getPassword()})
- if new_url != pyfile.url:
- self.logDebug("New URL: %s" % new_url)
+ 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.download(new_url, disposition=True)
+ self.html = self.load("http://debriditalia.com/linkgen2.php",
+ post={'xjxfun' : "convertiLink",
+ 'xjxargs[]': "S<![CDATA[%s]]>" % self.pyfile.url,
+ 'xjxargs[]': "S%s" % self.getPassword()})
+ try:
+ self.link = re.search(r'<a href="(.+?)"', self.html).group(1)
+ except AttributeError:
+ pass
- check = self.checkDownload({"empty": re.compile(r"^$")})
- if check == "empty":
- self.retry(5, 2 * 60, "Empty file downloaded")
+getInfo = create_getInfo(DebridItaliaCom)
diff --git a/module/plugins/hoster/DepositfilesCom.py b/module/plugins/hoster/DepositfilesCom.py
index 15e23cba7..6588a3b37 100644
--- a/module/plugins/hoster/DepositfilesCom.py
+++ b/module/plugins/hoster/DepositfilesCom.py
@@ -2,35 +2,38 @@
import re
+from urllib import unquote
+
from module.plugins.internal.CaptchaService import ReCaptcha
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class DepositfilesCom(SimpleHoster):
- __name__ = "DepositfilesCom"
- __version__ = "0.47"
- __type__ = "hoster"
+ __name__ = "DepositfilesCom"
+ __type__ = "hoster"
+ __version__ = "0.51"
__pattern__ = r'https?://(?:www\.)?(depositfiles\.com|dfiles\.(eu|ru))(/\w{1,3})?/files/(?P<ID>\w+)'
__description__ = """Depositfiles.com hoster plugin"""
- __author_name__ = ("spoob", "zoidberg", "Walter Purcaro")
- __author_mail__ = ("spoob@pyload.org", "zoidberg@mujmail.cz", "vuolter@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
- FILE_NAME_PATTERN = r'<script type="text/javascript">eval\( unescape\(\'(?P<N>.*?)\''
- FILE_SIZE_PATTERN = r': <b>(?P<S>[0-9.]+)&nbsp;(?P<U>[kKMG])i?B</b>'
+ NAME_PATTERN = r'<script type="text/javascript">eval\( unescape\(\'(?P<N>.*?)\''
+ SIZE_PATTERN = r': <b>(?P<S>[\d.,]+)&nbsp;(?P<U>[\w^_]+)</b>'
OFFLINE_PATTERN = r'<span class="html_download_api-not_exists"></span>'
- FILE_NAME_REPLACEMENTS = [(r'\%u([0-9A-Fa-f]{4})', lambda m: unichr(int(m.group(1), 16))),
+ NAME_REPLACEMENTS = [(r'\%u([0-9A-Fa-f]{4})', lambda m: unichr(int(m.group(1), 16))),
(r'.*<b title="(?P<N>[^"]+).*', "\g<N>")]
- FILE_URL_REPLACEMENTS = [(__pattern__, "https://dfiles.eu/files/\g<ID>")]
-
- SH_COOKIES = [(".dfiles.eu", "lang_current", "en")]
+ URL_REPLACEMENTS = [(__pattern__ + ".*", "https://dfiles.eu/files/\g<ID>")]
- RECAPTCHA_PATTERN = r"Recaptcha.create\('([^']+)'"
+ COOKIES = [("dfiles.eu", "lang_current", "en")]
- FREE_LINK_PATTERN = r'<form id="downloader_file_form" action="(http://.+?\.(dfiles\.eu|depositfiles\.com)/.+?)" method="post"'
- PREMIUM_LINK_PATTERN = r'class="repeat"><a href="(.+?)"'
+ FREE_LINK_PATTERN = r'<form id="downloader_file_form" action="(http://.+?\.(dfiles\.eu|depositfiles\.com)/.+?)" method="post"'
+ PREMIUM_LINK_PATTERN = r'class="repeat"><a href="(.+?)"'
PREMIUM_MIRROR_PATTERN = r'class="repeat_mirror"><a href="(.+?)"'
@@ -38,21 +41,20 @@ class DepositfilesCom(SimpleHoster):
self.html = self.load(self.pyfile.url, post={"gateway_result": "1"}, cookies=True)
if re.search(r'File is checked, please try again in a minute.', self.html) is not None:
- self.logInfo("DepositFiles.com: The file is being checked. Waiting 1 minute.")
- self.wait(61)
- self.retry()
+ 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("%s: Traffic used up. Waiting %d seconds." % (self.__name__, wait_time))
+ 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("%s: All free slots occupied. Waiting %d minutes." % (self.__name__, wait_time))
+ 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)
@@ -65,21 +67,16 @@ class DepositfilesCom(SimpleHoster):
params = {'fid': m.group(1)}
self.logDebug("FID: %s" % params['fid'])
- captcha_key = '6LdRTL8SAAAAAE9UOdWZ4d0Ky-aeA7XfSqyWDM2m'
- m = re.search(self.RECAPTCHA_PATTERN, self.html)
- if m:
- captcha_key = m.group(1)
- self.logDebug("CAPTCHA_KEY: %s" % captcha_key)
-
self.wait()
recaptcha = ReCaptcha(self)
+ captcha_key = recaptcha.detect_key()
+ if captcha_key is None:
+ self.error(_("ReCaptcha key not found"))
- for _ in xrange(5):
+ 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 not captcha_key:
- self.parseError('Captcha key')
if 'response' in params:
self.invalidCaptcha()
params['challenge'], params['response'] = recaptcha.challenge(captcha_key)
@@ -94,20 +91,19 @@ class DepositfilesCom(SimpleHoster):
self.logDebug("LINK: %s" % link)
break
else:
- self.parseError('Download link')
+ self.error(_("Download link"))
else:
- self.fail('No valid captcha response received')
+ self.fail(_("No valid captcha response received"))
try:
self.download(link, disposition=True)
except:
self.retry(wait_time=60)
- def handlePremium(self):
- self.html = self.load(self.pyfile.url, cookies=self.SH_COOKIES)
+ def handlePremium(self):
if '<span class="html_download_api-gold_traffic_limit">' in self.html:
- self.logWarning("Download limit reached")
+ 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)
@@ -120,7 +116,8 @@ class DepositfilesCom(SimpleHoster):
elif mirror:
dlink = mirror.group(1)
else:
- self.parseError("No direct download link or mirror found")
+ self.error(_("No direct download link or mirror found"))
self.download(dlink, disposition=True)
+
getInfo = create_getInfo(DepositfilesCom)
diff --git a/module/plugins/hoster/DevhostSt.py b/module/plugins/hoster/DevhostSt.py
new file mode 100644
index 000000000..85e36edb3
--- /dev/null
+++ b/module/plugins/hoster/DevhostSt.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+#
+# Test links:
+# http://d-h.st/mM8
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class DevhostSt(SimpleHoster):
+ __name__ = "DevhostSt"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
+ __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'>Filename:</span> <div title="(?P<N>.+?)"'
+ SIZE_PATTERN = r'>Size:</span> (?P<S>[\d.,]+) (?P<U>[\w^_]+)'
+
+ OFFLINE_PATTERN = r'>File Not Found<'
+ LINK_PATTERN = r'id="downloadfile" href="(.+?)"'
+
+
+ def setup(self):
+ self.multiDL = True
+ self.chunkLimit = 1
+
+
+ def handleFree(self):
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ self.error(_("Download link not found"))
+
+ dl_url = m.group(1)
+ self.download(dl_url, disposition=True)
+
+ check = self.checkDownload({'html': re.compile("html")})
+ if check == "html":
+ self.error(_("Downloaded file is an html page"))
+
+
+getInfo = create_getInfo(DevhostSt)
diff --git a/module/plugins/hoster/DlFreeFr.py b/module/plugins/hoster/DlFreeFr.py
index 5fb527136..793c81b1c 100644
--- a/module/plugins/hoster/DlFreeFr.py
+++ b/module/plugins/hoster/DlFreeFr.py
@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
-import re
import pycurl
+import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns
-from module.common.json_layer import json_loads
from module.network.Browser import Browser
from module.network.CookieJar import CookieJar
+from module.plugins.internal.CaptchaService import AdYouLike
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns
class CustomBrowser(Browser):
@@ -14,6 +14,7 @@ class CustomBrowser(Browser):
def __init__(self, bucket=None, options={}):
Browser.__init__(self, bucket, options)
+
def load(self, *args, **kwargs):
post = kwargs.get("post")
@@ -32,111 +33,42 @@ class CustomBrowser(Browser):
return Browser.load(self, *args, **kwargs)
-class AdYouLike:
- """
- Class to support adyoulike captcha service
- """
- ADYOULIKE_INPUT_PATTERN = r'Adyoulike.create\((.*?)\);'
- ADYOULIKE_CALLBACK = r'Adyoulike.g._jsonp_5579316662423138'
- ADYOULIKE_CHALLENGE_PATTERN = ADYOULIKE_CALLBACK + r'\((.*?)\)'
-
- def __init__(self, plugin, engine="adyoulike"):
- self.plugin = plugin
- self.engine = engine
-
- def challenge(self, html):
- adyoulike_data_string = None
- m = re.search(self.ADYOULIKE_INPUT_PATTERN, html)
- if m:
- adyoulike_data_string = m.group(1)
- else:
- self.plugin.fail("Can't read AdYouLike input data")
-
- # {"adyoulike":{"key":"P~zQ~O0zV0WTiAzC-iw0navWQpCLoYEP"},
- # "all":{"element_id":"ayl_private_cap_92300","lang":"fr","env":"prod"}}
- ayl_data = json_loads(adyoulike_data_string)
-
- res = self.plugin.load(
- r'http://api-ayl.appspot.com/challenge?key=%(ayl_key)s&env=%(ayl_env)s&callback=%(callback)s' % {
- "ayl_key": ayl_data[self.engine]['key'], "ayl_env": ayl_data['all']['env'],
- "callback": self.ADYOULIKE_CALLBACK})
-
- m = re.search(self.ADYOULIKE_CHALLENGE_PATTERN, res)
- challenge_string = None
- if m:
- challenge_string = m.group(1)
- else:
- self.plugin.fail("Invalid AdYouLike challenge")
- challenge_data = json_loads(challenge_string)
-
- return ayl_data, challenge_data
-
- def result(self, ayl, 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"})
- """
- response = None
- try:
- instructions_visual = challenge['translations'][ayl['all']['lang']]['instructions_visual']
- m = re.search(u".*«(.*)».*", instructions_visual)
- if m:
- response = m.group(1).strip()
- else:
- self.plugin.fail("Can't parse instructions visual")
- except KeyError:
- self.plugin.fail("No instructions visual")
-
- #TODO: Supports captcha
-
- if not response:
- self.plugin.fail("AdYouLike result failed")
-
- return {"_ayl_captcha_engine": self.engine,
- "_ayl_env": ayl['all']['env'],
- "_ayl_tid": challenge['tid'],
- "_ayl_token_challenge": challenge['token'],
- "_ayl_response": response}
+class DlFreeFr(SimpleHoster):
+ __name__ = "DlFreeFr"
+ __type__ = "hoster"
+ __version__ = "0.26"
+ __pattern__ = r'http://(?:www\.)?dl\.free\.fr/(\w+|getfile\.pl\?file=/\w+)'
-class DlFreeFr(SimpleHoster):
- __name__ = "DlFreeFr"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?dl\.free\.fr/([a-zA-Z0-9]+|getfile\.pl\?file=/[a-zA-Z0-9]+)'
- __version__ = "0.25"
__description__ = """Dl.free.fr hoster plugin"""
- __author_name__ = ("the-razer", "zoidberg", "Toilal")
- __author_mail__ = ("daniel_ AT gmx DOT net", "zoidberg@mujmail.cz", "toilal.dev@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("the-razer", "daniel_ AT gmx DOT net"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("Toilal", "toilal.dev@gmail.com")]
- FILE_NAME_PATTERN = r'Fichier:</td>\s*<td[^>]*>(?P<N>[^>]*)</td>'
- FILE_SIZE_PATTERN = r'Taille:</td>\s*<td[^>]*>(?P<S>[\d.]+[KMG])o'
- OFFLINE_PATTERN = r"Erreur 404 - Document non trouv|Fichier inexistant|Le fichier demand&eacute; n'a pas &eacute;t&eacute; trouv&eacute;"
+
+ 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&eacute; n\'a pas &eacute;t&eacute; trouv&eacute;'
def setup(self):
- self.multiDL = self.resumeDownload = True
- self.limitDL = 5
- self.chunkLimit = 1
+ 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):
- self.req.setCookieJar(None)
- pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS)
+ 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)
- self.html = None
if headers.get('code') == 302:
valid_url = headers.get('location')
headers = self.load(valid_url, just_header=True)
@@ -148,20 +80,19 @@ class DlFreeFr(SimpleHoster):
self.html = self.load(valid_url)
self.handleFree()
else:
- # Direct access to requested file for users using free.fr as Internet Service Provider.
+ # Direct access to requested file for users using free.fr as Internet Service Provider.
self.download(valid_url, disposition=True)
elif headers.get('code') == 404:
self.offline()
else:
- self.fail("Invalid return code: " + str(headers.get('code')))
+ self.fail(_("Invalid return code: ") + str(headers.get('code')))
+
def handleFree(self):
action, inputs = self.parseHtmlForm('action="getfile.pl"')
adyoulike = AdYouLike(self)
- ayl, challenge = adyoulike.challenge(self.html)
- result = adyoulike.result(ayl, challenge)
- inputs.update(result)
+ inputs.update(adyoulike.challenge())
self.load("http://dl.free.fr/getfile.pl", post=inputs)
headers = self.getLastHeaders()
@@ -171,12 +102,13 @@ class DlFreeFr(SimpleHoster):
if m:
cj.setCookie(m.group(4), m.group(1), m.group(2), m.group(3))
else:
- self.fail("Cookie error")
+ self.fail(_("Cookie error"))
location = headers.get("location")
self.req.setCookieJar(cj)
self.download(location, disposition=True)
else:
- self.fail("Invalid response")
+ self.fail(_("Invalid response"))
+
def getLastHeaders(self):
#parse header
diff --git a/module/plugins/hoster/DodanePl.py b/module/plugins/hoster/DodanePl.py
new file mode 100644
index 000000000..65d8452fa
--- /dev/null
+++ b/module/plugins/hoster/DodanePl.py
@@ -0,0 +1,18 @@
+# -*- 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/DropboxCom.py b/module/plugins/hoster/DropboxCom.py
new file mode 100644
index 000000000..658974d13
--- /dev/null
+++ b/module/plugins/hoster/DropboxCom.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class DropboxCom(SimpleHoster):
+ __name__ = "DropboxCom"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
+ __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'&nbsp;&middot;&nbsp; (?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):
+ self.download(self.pyfile.url, get={'dl': "1"})
+
+ check = self.checkDownload({'html': re.compile("html")})
+ if check == "html":
+ self.error(_("Downloaded file is an html page"))
+
+
+getInfo = create_getInfo(DropboxCom)
diff --git a/module/plugins/hoster/DuploadOrg.py b/module/plugins/hoster/DuploadOrg.py
index 5909f7ccf..73702eb67 100644
--- a/module/plugins/hoster/DuploadOrg.py
+++ b/module/plugins/hoster/DuploadOrg.py
@@ -1,34 +1,18 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-class DuploadOrg(XFileSharingPro):
- __name__ = "DuploadOrg"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?dupload\.org/\w{12}'
- __version__ = "0.01"
- __description__ = """Dupload.grg hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+class DuploadOrg(DeadHoster):
+ __name__ = "DuploadOrg"
+ __type__ = "hoster"
+ __version__ = "0.02"
- HOSTER_NAME = "dupload.org"
+ __pattern__ = r'http://(?:www\.)?dupload\.org/\w{12}'
- FILE_INFO_PATTERN = r'<h3[^>]*>(?P<N>.+) \((?P<S>[\d.]+) (?P<U>\w+)\)</h3>'
+ __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
index c10c22fd9..cd54bdc70 100644
--- a/module/plugins/hoster/EasybytezCom.py
+++ b/module/plugins/hoster/EasybytezCom.py
@@ -1,43 +1,26 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+class EasybytezCom(XFSHoster):
+ __name__ = "EasybytezCom"
+ __type__ = "hoster"
+ __version__ = "0.23"
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+ __pattern__ = r'http://(?:www\.)?easybytez\.com/\w{12}'
-
-class EasybytezCom(XFileSharingPro):
- __name__ = "EasybytezCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?easybytez.com/(\w+).*'
- __version__ = "0.17"
__description__ = """Easybytez.com hoster plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
- HOSTER_NAME = "easybytez.com"
- FILE_INFO_PATTERN = r'<span class="name">(?P<N>.+)</span><br>\s*<span class="size">(?P<S>[^<]+)</span>'
- OFFLINE_PATTERN = r'<h1>File not available</h1>'
+ HOSTER_DOMAIN = "easybytez.com"
- LINK_PATTERN = r'(http://(\w+\.(easyload|easybytez|zingload)\.(com|to)|\d+\.\d+\.\d+\.\d+)/files/\d+/\w+/[^"<]+)'
- OVR_LINK_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)'
- ERROR_PATTERN = r'(?:class=["\']err["\'][^>]*>|<Center><b>)(.*?)</'
+ OFFLINE_PATTERN = r'>File not available'
- def setup(self):
- self.resumeDownload = self.multiDL = self.premium
+ 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
index f0715bfc7..eb9338871 100644
--- a/module/plugins/hoster/EdiskCz.py
+++ b/module/plugins/hoster/EdiskCz.py
@@ -1,51 +1,41 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class EdiskCz(SimpleHoster):
- __name__ = "EdiskCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?edisk.(cz|sk|eu)/(stahni|sk/stahni|en/download)/.*'
- __version__ = "0.21"
+ __name__ = "EdiskCz"
+ __type__ = "hoster"
+ __version__ = "0.22"
+
+ __pattern__ = r'http://(?:www\.)?edisk\.(cz|sk|eu)/(stahni|sk/stahni|en/download)/.+'
+
__description__ = """Edisk.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_INFO_PATTERN = r'<span class="fl" title="(?P<N>[^"]+)">\s*.*?\((?P<S>[0-9.]*) (?P<U>[kKMG])i?B\)</h1></span>'
+
+ 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_PATTERN = r'http://.*edisk.cz.*\.html'
+ LINK_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)
+ self.logDebug("URL:" + url)
m = re.search(self.ACTION_PATTERN, url)
if m is None:
- self.parseError("ACTION")
+ self.error(_("ACTION_PATTERN not found"))
action = m.group(1)
self.html = self.load(url, decode=True)
@@ -58,7 +48,7 @@ class EdiskCz(SimpleHoster):
})
if not re.match(self.LINK_PATTERN, url):
- self.fail("Unexpected server response")
+ self.fail(_("Unexpected server response"))
self.download(url)
diff --git a/module/plugins/hoster/EgoFilesCom.py b/module/plugins/hoster/EgoFilesCom.py
index f4fdda5a3..9a2f50ed4 100644
--- a/module/plugins/hoster/EgoFilesCom.py
+++ b/module/plugins/hoster/EgoFilesCom.py
@@ -1,101 +1,18 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-# Test link (random.bin):
-# http://egofiles.com/mOZfMI1WLZ6HBkGG/random.bin
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-from module.plugins.internal.CaptchaService import ReCaptcha
+class EgoFilesCom(DeadHoster):
+ __name__ = "EgoFilesCom"
+ __type__ = "hoster"
+ __version__ = "0.16"
+ __pattern__ = r'https?://(?:www\.)?egofiles\.com/\w+'
-class EgoFilesCom(SimpleHoster):
- __name__ = "EgoFilesCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?egofiles.com/(\w+)'
- __version__ = "0.15"
__description__ = """Egofiles.com hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- FILE_INFO_PATTERN = r'<div class="down-file">\s+(?P<N>[^\t]+)\s+<div class="file-properties">\s+(File size|Rozmiar): (?P<S>[\w.]+) (?P<U>\w+) \|'
- OFFLINE_PATTERN = r'(File size|Rozmiar): 0 KB'
- WAIT_TIME_PATTERN = r'For next free download you have to wait <strong>((?P<m>\d*)m)? ?((?P<s>\d+)s)?</strong>'
- LINK_PATTERN = r'<a href="(?P<link>[^"]+)">Download ></a>'
- RECAPTCHA_KEY = "6LeXatQSAAAAAHezcjXyWAni-4t302TeYe7_gfvX"
-
-
- def setup(self):
- # Set English language
- self.load("https://egofiles.com/ajax/lang.php?lang=en", just_header=True)
-
- def process(self, pyfile):
- if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()):
- self.handlePremium()
- else:
- self.handleFree()
-
- def handleFree(self):
- self.html = self.load(self.pyfile.url, decode=True)
- self.getFileInfo()
-
- # Wait time between free downloads
- if 'For next free download you have to wait' in self.html:
- m = re.search(self.WAIT_TIME_PATTERN, self.html).groupdict('0')
- waittime = int(m['m']) * 60 + int(m['s'])
- self.wait(waittime, True)
-
- downloadURL = r''
- recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
- post_data = {'recaptcha_challenge_field': challenge,
- 'recaptcha_response_field': response}
- self.html = self.load(self.pyfile.url, post=post_data, decode=True)
- m = re.search(self.LINK_PATTERN, self.html)
- if m is None:
- self.logInfo('Wrong captcha')
- self.invalidCaptcha()
- elif hasattr(m, 'group'):
- downloadURL = m.group('link')
- self.correctCaptcha()
- break
- else:
- self.fail('Unknown error - Plugin may be out of date')
-
- if not downloadURL:
- self.fail("No Download url retrieved/all captcha attempts failed")
-
- self.download(downloadURL, disposition=True)
-
- def handlePremium(self):
- header = self.load(self.pyfile.url, just_header=True)
- if 'location' in header:
- self.logDebug('DIRECT LINK from header: ' + header['location'])
- self.download(header['location'])
- else:
- self.html = self.load(self.pyfile.url, decode=True)
- self.getFileInfo()
- m = re.search(r'<a href="(?P<link>[^"]+)">Download ></a>', self.html)
- if m is None:
- self.parseError('Unable to detect direct download url')
- else:
- self.logDebug('DIRECT URL from html: ' + m.group('link'))
- self.download(m.group('link'), disposition=True)
+ __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
new file mode 100644
index 000000000..bbd613f57
--- /dev/null
+++ b/module/plugins/hoster/EnteruploadCom.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
index 062c8186f..8ac8cdaf2 100644
--- a/module/plugins/hoster/EpicShareNet.py
+++ b/module/plugins/hoster/EpicShareNet.py
@@ -1,24 +1,18 @@
# -*- coding: utf-8 -*-
-# Test links:
-# BigBuckBunny_320x180.mp4 - 61.7 Mb - http://epicshare.net/fch3m2bk6ihp/BigBuckBunny_320x180.mp4.html
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+class EpicShareNet(DeadHoster):
+ __name__ = "EpicShareNet"
+ __type__ = "hoster"
+ __version__ = "0.02"
-class EpicShareNet(XFileSharingPro):
- __name__ = "EpicShareNet"
- __type__ = "hoster"
__pattern__ = r'https?://(?:www\.)?epicshare\.net/\w{12}'
- __version__ = "0.01"
- __description__ = """EpicShare.net hoster plugin"""
- __author_name__ = "t4skforce"
- __author_mail__ = "t4skforce1337[AT]gmail[DOT]com"
-
- HOSTER_NAME = "epicshare.net"
- OFFLINE_PATTERN = r'<b>File Not Found</b><br><br>'
- FILE_NAME_PATTERN = r'<b>Password:</b></div>\s*<h2>(?P<N>[^<]+)</h2>'
+ __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
index 5365e7312..cc10abb37 100644
--- a/module/plugins/hoster/EuroshareEu.py
+++ b/module/plugins/hoster/EuroshareEu.py
@@ -1,51 +1,41 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class EuroshareEu(SimpleHoster):
- __name__ = "EuroshareEu"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?euroshare.(eu|sk|cz|hu|pl)/file/.*'
- __version__ = "0.25"
+ __name__ = "EuroshareEu"
+ __type__ = "hoster"
+ __version__ = "0.26"
+
+ __pattern__ = r'http://(?:www\.)?euroshare\.(eu|sk|cz|hu|pl)/file/.+'
+
__description__ = """Euroshare.eu hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_INFO_PATTERN = r'<span style="float: left;"><strong>(?P<N>.+?)</strong> \((?P<S>.+?)\)</span>'
+ 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!'
FREE_URL_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/"'
- FILE_URL_REPLACEMENTS = [(r"(http://[^/]*\.)(sk|cz|hu|pl)/", r"\1eu/")]
+ URL_REPLACEMENTS = [(r"(http://[^/]*\.)(sk|cz|hu|pl)/", r"\1eu/")]
def setup(self):
self.multiDL = self.resumeDownload = self.premium
self.req.setOption("timeout", 120)
+
def handlePremium(self):
if self.ERR_NOT_LOGGED_IN_PATTERN in self.html:
self.account.relogin(self.user)
- self.retry(reason="User not logged in")
+ self.retry(reason=_("User not logged in"))
self.download(self.pyfile.url.rstrip('/') + "/download/")
@@ -53,17 +43,18 @@ class EuroshareEu(SimpleHoster):
"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")
+ self.retry(reason=_("Access token expired"))
elif check == "json":
self.fail(self.lastCheck.group(1))
+
def handleFree(self):
if re.search(self.ERR_PARDL_PATTERN, self.html) is not None:
self.longWait(5 * 60, 12)
m = re.search(self.FREE_URL_PATTERN, self.html)
if m is None:
- self.parseError("Parse error (URL)")
+ self.error(_("FREE_URL_PATTERN not found"))
parsed_url = "http://euroshare.eu%s" % m.group(1)
self.logDebug("URL", parsed_url)
self.download(parsed_url, disposition=True)
diff --git a/module/plugins/hoster/ExtabitCom.py b/module/plugins/hoster/ExtabitCom.py
index fac7922db..7609954d3 100644
--- a/module/plugins/hoster/ExtabitCom.py
+++ b/module/plugins/hoster/ExtabitCom.py
@@ -1,88 +1,77 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from module.common.json_layer import json_loads
-from module.plugins.hoster.UnrestrictLi import secondsToMidnight
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, secondsToMidnight
class ExtabitCom(SimpleHoster):
- __name__ = "ExtabitCom"
- __type__ = "hoster"
+ __name__ = "ExtabitCom"
+ __type__ = "hoster"
+ __version__ = "0.63"
+
__pattern__ = r'http://(?:www\.)?extabit\.com/(file|go|fid)/(?P<ID>\w+)'
- __version__ = "0.6"
+
__description__ = """Extabit.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<th>File:</th>\s*<td class="col-fileinfo">\s*<div title="(?P<N>[^"]+)">'
- FILE_SIZE_PATTERN = r'<th>Size:</th>\s*<td class="col-fileinfo">(?P<S>[^<]+)</td>'
+
+ 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_PATTERN = r'[\'"](http://guest\d+\.extabit\.com/[a-z0-9]+/.*?)[\'"]'
+ LINK_PATTERN = r'[\'"](http://guest\d+\.extabit\.com/\w+/.*?)[\'"]'
+
def handleFree(self):
if r">Only premium users can download this file" in self.html:
- self.fail("Only premium users can download this file")
+ 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.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.file_info('ID')
+ fileID = m.group('ID') if m else self.info('ID')
m = re.search(r'recaptcha/api/challenge\?k=(\w+)', self.html)
if m:
recaptcha = ReCaptcha(self)
captcha_key = m.group(1)
- for _ in xrange(5):
+ for _i in xrange(5):
get_data = {"type": "recaptcha"}
get_data['challenge'], get_data['capture'] = recaptcha.challenge(captcha_key)
- response = json_loads(self.load("http://extabit.com/file/%s/" % fileID, get=get_data))
- if "ok" in response:
+ 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")
+ self.fail(_("Invalid captcha"))
else:
- self.parseError('Captcha')
+ self.error(_("Captcha"))
- if not "href" in response:
- self.parseError('JSON')
+ if not "href" in res:
+ self.error(_("Bad JSON response"))
+
+ self.html = self.load("http://extabit.com/file/%s%s" % (fileID, res['href']))
- self.html = self.load("http://extabit.com/file/%s%s" % (fileID, response['href']))
m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.parseError('Download URL')
+ self.error(_("LINK_PATTERN not found"))
+
url = m.group(1)
- self.logDebug("Download URL: " + url)
self.download(url)
diff --git a/module/plugins/hoster/FastixRu.py b/module/plugins/hoster/FastixRu.py
index a59fae498..5f6fd2d4c 100644
--- a/module/plugins/hoster/FastixRu.py
+++ b/module/plugins/hoster/FastixRu.py
@@ -1,20 +1,25 @@
# -*- coding: utf-8 -*-
import re
-from urllib import unquote
+
from random import randrange
-from module.plugins.Hoster import Hoster
+from urllib import unquote
+
from module.common.json_layer import json_loads
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
-class FastixRu(Hoster):
- __name__ = "FastixRu"
- __version__ = "0.04"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?fastix\.(ru|it)/file/(?P<ID>[a-zA-Z0-9]{24})'
+class FastixRu(MultiHoster):
+ __name__ = "FastixRu"
+ __type__ = "hoster"
+ __version__ = "0.08"
+
+ __pattern__ = r'http://(?:www\.)?fastix\.(ru|it)/file/\w{24}'
+
__description__ = """Fastix hoster plugin"""
- __author_name__ = "Massimo Rosamilia"
- __author_mail__ = "max@spiritix.eu"
+ __license__ = "GPLv3"
+ __authors__ = [("Massimo Rosamilia", "max@spiritix.eu")]
+
def getFilename(self, url):
try:
@@ -25,42 +30,40 @@ class FastixRu(Hoster):
name += "%s.tmp" % randrange(100, 999)
return name
+
def setup(self):
- self.chunkLimit = 3
+ self.chunkLimit = 3
self.resumeDownload = True
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "Fastix")
- self.fail("No Fastix account provided")
+
+ def handlePremium(self):
+ api_key = self.account.getAccountData(self.user)
+ api_key = api_key['api']
+
+ page = self.load("http://fastix.ru/api_v2/",
+ get={'apikey': api_key, 'sub': "getdirectlink", 'link': self.pyfile.url})
+ data = json_loads(page)
+
+ self.logDebug("Json data", data)
+
+ if "error\":true" in page:
+ self.offline()
else:
- self.logDebug("Old URL: %s" % pyfile.url)
- api_key = self.account.getAccountData(self.user)
- api_key = api_key['api']
- url = "http://fastix.ru/api_v2/?apikey=%s&sub=getdirectlink&link=%s" % (api_key, pyfile.url)
- page = self.load(url)
- data = json_loads(page)
- self.logDebug("Json data: %s" % str(data))
- if "error\":true" in page:
- self.offline()
- else:
- new_url = data['downloadlink']
-
- if new_url != pyfile.url:
- self.logDebug("New URL: %s" % new_url)
-
- if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"):
+ self.link = data['downloadlink']
+
+ if self.link != self.pyfile.url:
+ self.logDebug("New URL: %s" % self.link)
+
+ if self.pyfile.name.startswith("http") or self.pyfile.name.startswith("Unknown"):
#only use when name wasnt already set
- pyfile.name = self.getFilename(new_url)
+ self.pyfile.name = self.getFilename(self.link)
+
+
+ def checkFile(self):
+ super(FastixRu, self).checkFile()
- self.download(new_url, disposition=True)
+ if self.checkDownload({"error": "<title>An error occurred while processing your request</title>"}) is "error":
+ self.retry(wait_time=60, reason=_("An error occurred while generating link"))
- check = self.checkDownload({"error": "<title>An error occurred while processing your request</title>",
- "empty": re.compile(r"^$")})
- if check == "error":
- self.retry(wait_time=60, reason="An error occurred while generating link.")
- elif check == "empty":
- self.retry(wait_time=60, reason="Downloaded File was empty.")
+getInfo = create_getInfo(FastixRu)
diff --git a/module/plugins/hoster/FastshareCz.py b/module/plugins/hoster/FastshareCz.py
index e1fd9a666..31437c6e7 100644
--- a/module/plugins/hoster/FastshareCz.py
+++ b/module/plugins/hoster/FastshareCz.py
@@ -1,98 +1,78 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-
-# Test links (random.bin):
-# http://www.fastshare.cz/2141189/random.bin
import re
+
from urlparse import urljoin
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class FastshareCz(SimpleHoster):
- __name__ = "FastshareCz"
- __type__ = "hoster"
+ __name__ = "FastshareCz"
+ __type__ = "hoster"
+ __version__ = "0.26"
+
__pattern__ = r'http://(?:www\.)?fastshare\.cz/\d+/.+'
- __version__ = "0.22"
+
__description__ = """FastShare.cz hoster plugin"""
- __author_name__ = ("zoidberg", "stickell", "Walter Purcaro")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it", "vuolter@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+ URL_REPLACEMENTS = [("#.*", "")]
+
+ COOKIES = [("fastshare.cz", "lang", "en")]
- FILE_INFO_PATTERN = r'<h1 class="dwp">(?P<N>[^<]+)</h1>\s*<div class="fileinfo">\s*Size\s*: (?P<S>\d+) (?P<U>\w+),'
+ 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)'
- FILE_URL_REPLACEMENTS = [("#.*", "")]
+ LINK_FREE_PATTERN = r'action=(/free/.*?)>\s*<img src="([^"]*)"><br'
+ LINK_PREMIUM_PATTERN = r'(http://data\d+\.fastshare\.cz/download\.php\?id=\d+&)'
- SH_COOKIES = [(".fastshare.cz", "lang", "en")]
+ SLOT_ERROR = "> 100% of FREE slots are full"
+ CREDIT_ERROR = " credit for "
- FREE_URL_PATTERN = r'action=(/free/.*?)>\s*<img src="([^"]*)"><br'
- PREMIUM_URL_PATTERN = r'(http://data\d+\.fastshare\.cz/download\.php\?id=\d+&)'
- CREDIT_PATTERN = r' 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):
- if "> 100% of FREE slots are full" in self.html:
- self.retry(120, 60, "No free slots")
+ def handleFree(self):
m = re.search(self.FREE_URL_PATTERN, self.html)
if m:
action, captcha_src = m.groups()
else:
- self.parseError("Free URL")
+ 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})
+ self.download(urljoin(baseurl, action), post={'code': captcha, 'btn.x': 77, 'btn.y': 18})
+
+
+ def checkFile(self):
+ super(FastshareCz, self).checkFile()
check = self.checkDownload({
- "paralell_dl":
- "<title>FastShare.cz</title>|<script>alert\('Pres FREE muzete stahovat jen jeden soubor najednou.'\)",
- "wrong_captcha": "Download for FREE"
+ '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")
+ self.retry(6, 10 * 60, _("Paralell download"))
- def handlePremium(self):
- header = self.load(self.pyfile.url, just_header=True)
- if "location" in header:
- url = header['location']
- else:
- self.html = self.load(self.pyfile.url)
-
- self.getFileInfo() #
-
- if self.CREDIT_PATTERN in self.html:
- self.logWarning("Not enough traffic left")
- self.resetAccount()
- else:
- m = re.search(self.PREMIUM_URL_PATTERN, self.html)
- if m:
- url = m.group(1)
- else:
- self.parseError("Premium URL")
-
- self.logDebug("PREMIUM URL: " + url)
- self.download(url, disposition=True)
+ elif check == "wrong_captcha":
+ self.retry(max_tries=5, reason=_("Wrong captcha"))
- check = self.checkDownload({"credit": re.compile(self.CREDIT_PATTERN)})
- if check == "credit":
+ elif check == "credit":
self.resetAccount()
diff --git a/module/plugins/hoster/File4safeCom.py b/module/plugins/hoster/File4safeCom.py
deleted file mode 100644
index bc0f20dbe..000000000
--- a/module/plugins/hoster/File4safeCom.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-from pycurl import FOLLOWLOCATION
-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-
-
-class File4safeCom(XFileSharingPro):
- __name__ = "File4safeCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?file4safe\.com/\w+'
- __version__ = "0.01"
- __description__ = """File4safe.com hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- HOSTER_NAME = "file4safe.com"
-
- def handlePremium(self):
- self.req.http.lastURL = self.pyfile.url
-
- self.req.http.c.setopt(FOLLOWLOCATION, 0)
- self.load(self.pyfile.url, post=self.getPostParameters(), decode=True)
- self.header = self.req.http.header
- self.req.http.c.setopt(FOLLOWLOCATION, 1)
-
- m = re.search(r"Location\s*:\s*(.*)", self.header, re.I)
- if m and re.match(self.LINK_PATTERN, m.group(1)):
- location = m.group(1).strip()
- self.startDownload(location)
- else:
- self.parseError("Unable to detect premium download link")
-
-
-getInfo = create_getInfo(File4safeCom)
diff --git a/module/plugins/hoster/FileApeCom.py b/module/plugins/hoster/FileApeCom.py
index 43625c92c..db843586b 100644
--- a/module/plugins/hoster/FileApeCom.py
+++ b/module/plugins/hoster/FileApeCom.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class FileApeCom(DeadHoster):
- __name__ = "FileApeCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?fileape\.com/(index\.php\?act=download\&id=|dl/)\w+'
+ __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"""
- __author_name__ = "espes"
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = [("espes", None)]
getInfo = create_getInfo(FileApeCom)
diff --git a/module/plugins/hoster/FileParadoxIn.py b/module/plugins/hoster/FileParadoxIn.py
index 6234c36df..0b5b57e22 100644
--- a/module/plugins/hoster/FileParadoxIn.py
+++ b/module/plugins/hoster/FileParadoxIn.py
@@ -2,22 +2,22 @@
import re
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class FileParadoxIn(XFileSharingPro):
- __name__ = "FileParadoxIn"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?fileparadox\.in/\w+'
- __version__ = "0.01"
+class FileParadoxIn(XFSHoster):
+ __name__ = "FileParadoxIn"
+ __type__ = "hoster"
+ __version__ = "0.04"
+
+ __pattern__ = r'https?://(?:www\.)?fileparadox\.in/\w{12}'
+
__description__ = """FileParadox.in hoster plugin"""
- __author_name__ = "RazorWing"
- __author_mail__ = "muppetuk1@hotmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("RazorWing", "muppetuk1@hotmail.com")]
- HOSTER_NAME = "fileparadox.in"
- FILE_SIZE_PATTERN = r'</font>\s*\(\s*(?P<S>[^)]+)\s*\)</font>'
- LINK_PATTERN = r'(http://([^/]*?fileparadox.in|\d+\.\d+\.\d+\.\d+)(:\d+/d/|/files/\w+/\w+/)[^"\'<]+)'
+ HOSTER_DOMAIN = "fileparadox.in"
getInfo = create_getInfo(FileParadoxIn)
diff --git a/module/plugins/hoster/FileSharkPl.py b/module/plugins/hoster/FileSharkPl.py
new file mode 100644
index 000000000..5250a92fe
--- /dev/null
+++ b/module/plugins/hoster/FileSharkPl.py
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from urlparse import urljoin
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class FileSharkPl(SimpleHoster):
+ __name__ = "FileSharkPl"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __pattern__ = r'http://(?:www\.)?fileshark\.pl/pobierz/\d{6}/\w{5}'
+
+ __description__ = """FileShark.pl hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("prOq", None),
+ ("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)
+
+
+ #@NOTE: handlePremium method was never been tested
+ def handlePremium(self):
+ super(FilerNet, self).handlePremium()
+ if self.link:
+ self.link = urljoin("http://fileshark.pl/", self.link)
+
+
+ def handleFree(self):
+ 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):
+ super(FileSharkPl, self).checkFile()
+
+ 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()
+
+
+ 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
index 37eec6684..e1bd8da71 100644
--- a/module/plugins/hoster/FileStoreTo.py
+++ b/module/plugins/hoster/FileStoreTo.py
@@ -1,45 +1,36 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class FileStoreTo(SimpleHoster):
- __name__ = "FileStoreTo"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?filestore\.to/\?d=(?P<ID>\w+)'
+ __name__ = "FileStoreTo"
+ __type__ = "hoster"
__version__ = "0.01"
+
+ __pattern__ = r'http://(?:www\.)?filestore\.to/\?d=(?P<ID>\w+)'
+
__description__ = """FileStore.to hoster plugin"""
- __author_name__ = ("Walter Purcaro", "stickell")
- __author_mail__ = ("vuolter@gmail.com", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
+
- FILE_INFO_PATTERN = r'File: <span[^>]*>(?P<N>.+)</span><br />Size: (?P<S>[\d,.]+) (?P<U>\w+)'
+ INFO_PATTERN = r'File: <span[^>]*>(?P<N>.+)</span><br />Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)'
OFFLINE_PATTERN = r'>Download-Datei wurde nicht gefunden<'
+
def setup(self):
- self.resumeDownload = self.multiDL = True
+ self.resumeDownload = True
+ self.multiDL = True
+
def handleFree(self):
self.wait(10)
ldc = re.search(r'wert="(\w+)"', self.html).group(1)
link = self.load("http://filestore.to/ajax/download.php", get={"LDC": ldc})
- self.logDebug("Download link = " + link)
self.download(link)
diff --git a/module/plugins/hoster/FilebeerInfo.py b/module/plugins/hoster/FilebeerInfo.py
index dd26b9120..885010a2c 100644
--- a/module/plugins/hoster/FilebeerInfo.py
+++ b/module/plugins/hoster/FilebeerInfo.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class FilebeerInfo(DeadHoster):
- __name__ = "FilebeerInfo"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?filebeer\.info/(?!\d*~f)(?P<ID>\w+).*'
+ __name__ = "FilebeerInfo"
+ __type__ = "hoster"
__version__ = "0.03"
+
+ __pattern__ = r'http://(?:www\.)?filebeer\.info/(?!\d*~f)(?P<ID>\w+)'
+
__description__ = """Filebeer.info plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
index 8fc1ddca2..8b6804a68 100644
--- a/module/plugins/hoster/FilecloudIo.py
+++ b/module/plugins/hoster/FilecloudIo.py
@@ -1,118 +1,116 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
from module.common.json_layer import json_loads
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class FilecloudIo(SimpleHoster):
- __name__ = "FilecloudIo"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(?:filecloud\.io|ifile\.it|mihd\.net)/(?P<ID>\w+).*'
- __version__ = "0.02"
+ __name__ = "FilecloudIo"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __pattern__ = r'http://(?:www\.)?(?:filecloud\.io|ifile\.it|mihd\.net)/(?P<ID>\w+)'
+
__description__ = """Filecloud.io hoster plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
- FILE_SIZE_PATTERN = r'{var __ab1 = (?P<S>\d+);}'
- FILE_NAME_PATTERN = r'id="aliasSpan">(?P<N>.*?)&nbsp;&nbsp;<'
- OFFLINE_PATTERN = r'l10n.(FILES__DOESNT_EXIST|REMOVED)'
- TEMP_OFFLINE_PATTERN = r'l10n.FILES__WARNING'
+ SIZE_PATTERN = r'{var __ab1 = (?P<S>\d+);}'
+ NAME_PATTERN = r'id="aliasSpan">(?P<N>.*?)&nbsp;&nbsp;<'
+ 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+)' \)"
+ UKEY_PATTERN = r'\'ukey\'\s*:\'(\w+)'
+ AB1_PATTERN = r'if\( __ab1 == \'(\w+)\' \)'
ERROR_MSG_PATTERN = r'var __error_msg\s*=\s*l10n\.(.*?);'
- LINK_PATTERN = r'"(http://s\d+.filecloud.io/%s/\d+/.*?)"'
- RECAPTCHA_KEY_PATTERN = r"var __recaptcha_public\s*=\s*'([^']+)';"
- RECAPTCHA_KEY = "6Lf5OdISAAAAAEZObLcx5Wlv4daMaASRov1ysDB1"
+ RECAPTCHA_PATTERN = r'var __recaptcha_public\s*=\s*\'(.+?)\';'
+
+ LINK_PATTERN = r'"(http://s\d+\.filecloud\.io/%s/\d+/.*?)"'
def setup(self):
- self.resumeDownload = self.multiDL = True
- self.chunkLimit = 1
+ self.resumeDownload = True
+ self.multiDL = True
+ self.chunkLimit = 1
+
def handleFree(self):
- data = {"ukey": self.file_info['ID']}
+ data = {"ukey": self.info['pattern']['ID']}
m = re.search(self.AB1_PATTERN, self.html)
if m is None:
- self.parseError("__AB1")
+ 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"))
+
if not self.account:
- self.fail("User not logged in")
+ self.fail(_("User not logged in"))
elif not self.account.logged_in:
- recaptcha = ReCaptcha(self)
- captcha_challenge, captcha_response = recaptcha.challenge(self.RECAPTCHA_KEY)
- self.account.form_data = {"recaptcha_challenge_field": captcha_challenge,
- "recaptcha_response_field": captcha_response}
+ challenge, response = 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"
- response = self.load(json_url, post=data)
- self.logDebug(response)
- response = json_loads(response)
-
- if "error" in response and response['error']:
- self.fail(response)
-
- self.logDebug(response)
- if response['captcha']:
- recaptcha = ReCaptcha(self)
- m = re.search(self.RECAPTCHA_KEY_PATTERN, self.html)
- captcha_key = m.group(1) if m else self.RECAPTCHA_KEY
+ 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 _ in xrange(5):
+ for _i in xrange(5):
data['recaptcha_challenge'], data['recaptcha_response'] = recaptcha.challenge(captcha_key)
json_url = "http://filecloud.io/download-request.json"
- response = self.load(json_url, post=data)
- self.logDebug(response)
- response = json_loads(response)
+ res = self.load(json_url, post=data)
+ self.logDebug(res)
+ res = json_loads(res)
- if "retry" in response and response['retry']:
+ if "retry" in res and res['retry']:
self.invalidCaptcha()
else:
self.correctCaptcha()
break
else:
- self.fail("Incorrect captcha")
+ self.fail(_("Incorrect captcha"))
- if response['dl']:
+ if res['dl']:
self.html = self.load('http://filecloud.io/download.html')
- m = re.search(self.LINK_PATTERN % self.file_info['ID'], self.html)
+
+ m = re.search(self.LINK_PATTERN % self.info['pattern']['ID'], self.html)
if m is None:
- self.parseError("Download URL")
- download_url = m.group(1)
- self.logDebug("Download URL: %s" % download_url)
+ self.error(_("LINK_PATTERN not found"))
+
+ if "size" in self.info and self.info['size']:
+ self.check_data = {"size": int(self.info['size'])}
- if "size" in self.file_info and self.file_info['size']:
- self.check_data = {"size": int(self.file_info['size'])}
+ download_url = m.group(1)
self.download(download_url)
else:
- self.fail("Unexpected server response")
+ self.fail(_("Unexpected server response"))
+
def handlePremium(self):
akey = self.account.getAccountData(self.user)['akey']
- ukey = self.file_info['ID']
+ 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})
diff --git a/module/plugins/hoster/FilefactoryCom.py b/module/plugins/hoster/FilefactoryCom.py
index 98a97121c..ada498a51 100644
--- a/module/plugins/hoster/FilefactoryCom.py
+++ b/module/plugins/hoster/FilefactoryCom.py
@@ -1,118 +1,90 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo
+from urlparse import urljoin
+
from module.network.RequestFactory import getURL
+from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo
def getInfo(urls):
for url in urls:
h = getURL(url, just_header=True)
m = re.search(r'Location: (.+)\r\n', h)
- if m and not re.match(m.group(1), FilefactoryCom.__pattern__): # It's a direct link! Skipping
+ if m and not re.match(m.group(1), FilefactoryCom.__pattern__): #: It's a direct link! Skipping
yield (url, 0, 3, url)
- else: # It's a standard html page
- file_info = parseFileInfo(FilefactoryCom, url, getURL(url))
- yield file_info
+ else: #: It's a standard html page
+ yield parseFileInfo(FilefactoryCom, url, getURL(url))
class FilefactoryCom(SimpleHoster):
- __name__ = "FilefactoryCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?filefactory\.com/file/(?P<id>[a-zA-Z0-9]+)'
- __version__ = "0.50"
+ __name__ = "FilefactoryCom"
+ __type__ = "hoster"
+ __version__ = "0.52"
+
+ __pattern__ = r'https?://(?:www\.)?filefactory\.com/(file|trafficshare/\w+)/\w+'
+
__description__ = """Filefactory.com hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
- FILE_INFO_PATTERN = r'<div id="file_name"[^>]*>\s*<h2>(?P<N>[^<]+)</h2>\s*<div id="file_info">\s*(?P<S>[\d.]+) (?P<U>\w+) uploaded'
- LINK_PATTERN = r'<a href="(https?://[^"]+)"[^>]*><i[^>]*></i> Download with FileFactory Premium</a>'
+ INFO_PATTERN = r'<div id="file_name"[^>]*>\s*<h2>(?P<N>[^<]+)</h2>\s*<div id="file_info">\s*(?P<S>[\d.,]+) (?P<U>[\w^_]+) uploaded'
OFFLINE_PATTERN = r'<h2>File Removed</h2>|This file is no longer available'
- PREMIUM_ONLY_PATTERN = r'>Premium Account Required<'
- SH_COOKIES = [(".filefactory.com", "locale", "en_US.utf8")]
+ LINK_PATTERN = r'"([^"]+filefactory\.com/get.+?)"'
+
+ WAIT_PATTERN = r'<div id="countdown_clock" data-delay="(\d+)">'
+ PREMIUM_ONLY_PATTERN = r'>Premium Account Required'
+
+ COOKIES = [("filefactory.com", "locale", "en_US.utf8")]
def handleFree(self):
- self.html = self.load(self.pyfile.url, decode=True)
if "Currently only Premium Members can download files larger than" in self.html:
- self.fail("File too large for free download")
+ self.fail(_("File too large for free download"))
elif "All free download slots on this server are currently in use" in self.html:
- self.retry(50, 15 * 60, "All free slots are busy")
+ self.retry(50, 15 * 60, _("All free slots are busy"))
- m = re.search(r'data-href(?:-direct)?="(http://[^"]+)"', self.html)
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ self.error(_("Free download link not found"))
+
+ dl_link = m.group(1)
+
+ m = re.search(self.WAIT_PATTERN, self.html)
if m:
- t = re.search(r'<div id="countdown_clock" data-delay="(\d+)">', self.html)
- if t:
- t = t.group(1)
- else:
- self.logDebug("Unable to detect countdown duration. Guessing 60 seconds")
- t = 60
- self.wait(t)
- direct = m.group(1)
- else: # This section could be completely useless now
- # Load the page that contains the direct link
- url = re.search(r"document\.location\.host \+\s*'(.+)';", self.html)
- if url is None:
- self.parseError('Unable to detect free link')
- url = 'http://www.filefactory.com' + url.group(1)
- self.html = self.load(url, decode=True)
-
- # Free downloads wait time
- waittime = re.search(r'id="startWait" value="(\d+)"', self.html)
- if not waittime:
- self.parseError('Unable to detect wait time')
- self.wait(int(waittime.group(1)))
-
- # Parse the direct link and download it
- direct = re.search(r'data-href(?:-direct)?="(.*)" class="button', self.html)
- if not direct:
- self.parseError('Unable to detect free direct link')
- direct = direct.group(1)
-
- self.logDebug('DIRECT LINK: ' + direct)
- self.download(direct, disposition=True)
-
- check = self.checkDownload({"multiple": "You are currently downloading too many files at once.",
- "error": '<div id="errorMessage">'})
+ self.wait(int(m.group(1)))
+
+ self.download(dl_link, disposition=True)
+
+ check = self.checkDownload({'multiple': "You are currently downloading too many files at once.",
+ 'error': '<div id="errorMessage">'})
if check == "multiple":
self.logDebug("Parallel downloads detected; waiting 15 minutes")
- self.retry(wait_time=15 * 60, reason="Parallel downloads")
+ self.retry(wait_time=15 * 60, reason=_("Parallel downloads"))
elif check == "error":
- self.fail("Unknown error")
+ self.error(_("Unknown error"))
+
def handlePremium(self):
header = self.load(self.pyfile.url, just_header=True)
+
if 'location' in header:
url = header['location'].strip()
if not url.startswith("http://"):
- url = "http://www.filefactory.com" + url
+ url = urljoin("http://www.filefactory.com", url)
elif 'content-disposition' in header:
url = self.pyfile.url
else:
- self.logInfo('You could enable "Direct Downloads" on http://filefactory.com/account/')
html = self.load(self.pyfile.url)
m = re.search(self.LINK_PATTERN, html)
if m:
url = m.group(1)
else:
- self.parseError('Unable to detect premium direct link')
+ self.error(_("Premium download link not found"))
- self.logDebug('DIRECT PREMIUM LINK: ' + url)
self.download(url, disposition=True)
diff --git a/module/plugins/hoster/FilejungleCom.py b/module/plugins/hoster/FilejungleCom.py
index ab582b3a3..8a8aee9e2 100644
--- a/module/plugins/hoster/FilejungleCom.py
+++ b/module/plugins/hoster/FilejungleCom.py
@@ -1,32 +1,20 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.hoster.FileserveCom import FileserveCom, checkFile
from module.plugins.Plugin import chunks
class FilejungleCom(FileserveCom):
- __name__ = "FilejungleCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?filejungle\.com/f/(?P<id>[^/]+).*'
+ __name__ = "FilejungleCom"
+ __type__ = "hoster"
__version__ = "0.51"
+
+ __pattern__ = r'http://(?:www\.)?filejungle\.com/f/(?P<ID>[^/]+)'
+
__description__ = """Filejungle.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
URLS = ["http://www.filejungle.com/f/", "http://www.filejungle.com/check_links.php",
"http://www.filejungle.com/checkReCaptcha.php"]
diff --git a/module/plugins/hoster/FileomCom.py b/module/plugins/hoster/FileomCom.py
index 7fd1efd34..2b6fd34db 100644
--- a/module/plugins/hoster/FileomCom.py
+++ b/module/plugins/hoster/FileomCom.py
@@ -1,50 +1,35 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-
-# Test links (random.bin):
+# Test links:
# http://fileom.com/gycaytyzdw3g/random.bin.html
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+class FileomCom(XFSHoster):
+ __name__ = "FileomCom"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __pattern__ = r'https?://(?:www\.)?fileom\.com/\w{12}'
-class FileomCom(XFileSharingPro):
- __name__ = "FileomCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?fileom\.com/\w+'
- __version__ = "0.01"
__description__ = """Fileom.com hoster plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- HOSTER_NAME = "fileom.com"
- FILE_URL_REPLACEMENTS = [(r'/$', "")]
- SH_COOKIES = [(".fileom.com", "lang", "english")]
+ HOSTER_DOMAIN = "fileom.com"
- FILE_NAME_PATTERN = r'Filename: <span>(?P<N>.+?)<'
- FILE_SIZE_PATTERN = r'File Size: <span class="size">(?P<S>[\d\.]+) (?P<U>\w+)'
+ NAME_PATTERN = r'Filename: <span>(?P<N>.+?)<'
+ SIZE_PATTERN = r'File Size: <span class="size">(?P<S>[\d.,]+) (?P<U>[\w^_]+)'
- ERROR_PATTERN = r'class=["\']err["\'][^>]*>(.*?)(?:\'|</)'
+ LINK_PATTERN = r'var url2 = \'(.+?)\';'
- LINK_PATTERN = r"var url2 = '(.+?)';"
def setup(self):
- self.resumeDownload = self.premium
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
index 93488236a..66c040770 100644
--- a/module/plugins/hoster/FilepostCom.py
+++ b/module/plugins/hoster/FilepostCom.py
@@ -1,87 +1,71 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-
-
- changelog:
- 0.27 - 2012-08-12 - hgg
- fix "global name 'js_answer' is not defined" bug
- fix captcha bug #1 (failed on non-english "captcha wrong" errors)
-"""
-
import re
+
from time import time
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-from module.plugins.internal.CaptchaService import ReCaptcha
from module.common.json_layer import json_loads
+from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class FilepostCom(SimpleHoster):
- __name__ = "FilepostCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?(?:filepost\.com/files|fp.io)/([^/]+).*'
- __version__ = "0.28"
+ __name__ = "FilepostCom"
+ __type__ = "hoster"
+ __version__ = "0.31"
+
+ __pattern__ = r'https?://(?:www\.)?(?:filepost\.com/files|fp\.io)/(?P<ID>[^/]+)'
+
__description__ = """Filepost.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_INFO_PATTERN = r'<input type="text" id="url" value=\'<a href[^>]*>(?P<N>[^>]+?) - (?P<S>[0-9\.]+ [kKMG]i?B)</a>\' class="inp_text"/>'
+ 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_KEY_PATTERN = r"Captcha.init\({\s*key:\s*'([^']+)'"
- FLP_TOKEN_PATTERN = r"set_store_options\({token: '([^']+)'"
+ RECAPTCHA_PATTERN = r'Captcha.init\({\s*key:\s*\'(.+?)\''
+ FLP_TOKEN_PATTERN = r'set_store_options\({token: \'(.+?)\''
- def handleFree(self):
- # Find token and captcha key
- file_id = re.match(self.__pattern__, self.pyfile.url).group(1)
+ def handleFree(self):
m = re.search(self.FLP_TOKEN_PATTERN, self.html)
if m is None:
- self.parseError("Token")
+ self.error(_("Token"))
flp_token = m.group(1)
- m = re.search(self.RECAPTCHA_KEY_PATTERN, self.html)
+ m = re.search(self.RECAPTCHA_PATTERN, self.html)
if m is None:
- self.parseError("Captcha key")
+ 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': file_id}
+ 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": file_id, "file_pass": ''}
+ post_dict = {"token": flp_token, "code": self.info['pattern']['ID'], "file_pass": ''}
if 'var is_pass_exists = true;' in self.html:
- # Solve password
- for file_pass in self.getPassword().splitlines():
+ # 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.logInfo("Password protected link, trying " + file_pass)
- download_url = self.getJsonResponse(get_dict, post_dict, 'link')
- if download_url:
- break
+ self.link = self.getJsonResponse(get_dict, post_dict, 'link')
+ if not self.link:
+ self.fail(_("Incorrect password"))
else:
- self.fail("No or incorrect password")
+ self.fail(_("No password found"))
else:
# Solve recaptcha
@@ -104,43 +88,46 @@ class FilepostCom(SimpleHoster):
self.invalidCaptcha()
else:
- self.fail("Invalid captcha")
+ self.fail(_("Invalid captcha"))
# Download
self.download(download_url)
+
def getJsonResponse(self, get_dict, post_dict, field):
- json_response = json_loads(self.load('https://filepost.com/files/get/', get=get_dict, post=post_dict))
- self.logDebug(json_response)
+ res = json_loads(self.load('https://filepost.com/files/get/', get=get_dict, post=post_dict))
- if not 'js' in json_response:
- self.parseError('JSON %s 1' % field)
+ self.logDebug(res)
- # i changed js_answer to json_response['js'] since js_answer is nowhere set.
+ 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 json_response['js']['error'] as well as js_answer['error'].
+ # accessed res['js']['error'] as well as js_answer['error'].
# see the two lines commented out with "# ~?".
- if 'error' in json_response['js']:
- if json_response['js']['error'] == 'download_delay':
- self.retry(wait_time=json_response['js']['params']['next_download'])
+ 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 json_response['js']['error']:
- return None
- elif 'You entered a wrong CAPTCHA code' in json_response['js']['error']:
- return None
- elif 'CAPTCHA Code nicht korrekt' in json_response['js']['error']:
+
+ 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 json_response['js']['error']:
- self.logDebug('error response is unknown, but mentions CAPTCHA -> return None')
+
+ elif 'CAPTCHA' in res['js']['error']:
+ self.logDebug("Error response is unknown, but mentions CAPTCHA")
return None
+
else:
- self.fail(json_response['js']['error'])
- # ~? self.fail(js_answer['error'])
+ self.fail(res['js']['error'])
- if not 'answer' in json_response['js'] or not field in json_response['js']['answer']:
- self.parseError('JSON %s 2' % field)
+ if not 'answer' in res['js'] or not field in res['js']['answer']:
+ self.error(_("JSON %s 2") % field)
- return json_response['js']['answer'][field]
+ return res['js']['answer'][field]
getInfo = create_getInfo(FilepostCom)
diff --git a/module/plugins/hoster/FilepupNet.py b/module/plugins/hoster/FilepupNet.py
new file mode 100644
index 000000000..cc3e86bc9
--- /dev/null
+++ b/module/plugins/hoster/FilepupNet.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+#
+# Test links:
+# http://www.filepup.net/files/k5w4ZVoF1410184283.html
+# http://www.filepup.net/files/R4GBq9XH1410186553.html
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class FilepupNet(SimpleHoster):
+ __name__ = "FilepupNet"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
+ __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_PATTERN = r'(http://www\.filepup\.net/get/.+?)\''
+
+
+ def setup(self):
+ self.multiDL = False
+ self.chunkLimit = 1
+
+
+ def handleFree(self):
+ m = re.search(self.LINK_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"})
+
+ check = self.checkDownload({'html': re.compile("html")})
+ if check == "html":
+ self.error(_("Downloaded file is an html page"))
+
+
+getInfo = create_getInfo(FilepupNet)
diff --git a/module/plugins/hoster/FilerNet.py b/module/plugins/hoster/FilerNet.py
index 91805ca40..2a38ac470 100644
--- a/module/plugins/hoster/FilerNet.py
+++ b/module/plugins/hoster/FilerNet.py
@@ -1,120 +1,82 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-# Test links (random.bin):
+#
+# Test links:
# http://filer.net/get/ivgf5ztw53et3ogd
# http://filer.net/get/hgo14gzcng3scbvv
import pycurl
import re
+
from urlparse import urljoin
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class FilerNet(SimpleHoster):
- __name__ = "FilerNet"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?filer\.net/get/(\w+)'
- __version__ = "0.03"
+ __name__ = "FilerNet"
+ __type__ = "hoster"
+ __version__ = "0.12"
+
+ __pattern__ = r'https?://(?:www\.)?filer\.net/get/\w+'
+
__description__ = """Filer.net hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
- FILE_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'
- RECAPTCHA_KEY = "6LcFctISAAAAAAgaeHgyqhNecGJJRnxV1m_vAz3V"
- LINK_PATTERN = r'href="([^"]+)">Get download</a>'
+ 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'
- def process(self, pyfile):
- if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()):
- self.handlePremium()
- else:
- self.handleFree()
+ LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'href="([^"]+)">Get download</a>'
- def handleFree(self):
- self.req.setOption("timeout", 120)
- self.html = self.load(self.pyfile.url, decode=not self.SH_BROKEN_ENCODING, cookies=self.SH_COOKIES)
+ def checkErrors(self):
# Wait between downloads
m = re.search(r'musst du <span id="time">(\d+)</span> Sekunden warten', self.html)
if m:
- waittime = int(m.group(1))
- self.retry(3, waittime, "Wait between free downloads")
+ errmsg = self.info['error'] = _("Wait between free downloads")
+ self.retry(wait_time=int(m.group(1)), reason=errmsg)
- self.getFileInfo()
+ self.info.pop('error', None)
- self.html = self.load(self.pyfile.url, decode=True)
- inputs = self.parseHtmlForm(input_names='token')[1]
+ def handleFree(self):
+ inputs = self.parseHtmlForm(input_names={'token': re.compile(r'.+')})[1]
if 'token' not in inputs:
- self.parseError('Unable to detect token')
- token = inputs['token']
- self.logDebug('Token: ' + token)
+ self.error(_("Unable to detect token"))
- self.html = self.load(self.pyfile.url, post={'token': token}, decode=True)
+ self.html = self.load(self.pyfile.url, post={'token': inputs['token']}, decode=True)
- inputs = self.parseHtmlForm(input_names='hash')[1]
+ inputs = self.parseHtmlForm(input_names={'hash': re.compile(r'.+')})[1]
if 'hash' not in inputs:
- self.parseError('Unable to detect hash')
- hash_data = inputs['hash']
- self.logDebug('Hash: ' + hash_data)
+ self.error(_("Unable to detect hash"))
- downloadURL = r''
recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
- post_data = {'recaptcha_challenge_field': challenge,
- 'recaptcha_response_field': response,
- 'hash': hash_data}
- # Workaround for 0.4.9 just_header issue. In 0.5 clean the code using just_header
+ for _i in xrange(5):
+ challenge, response = 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(self.pyfile.url, post=post_data)
+ self.load(self.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():
- location = re.search(r'location: (\S+)', self.req.http.header, re.I).group(1)
- downloadURL = urljoin('http://filer.net', location)
+ self.link = re.search(r'location: (\S+)', self.req.http.header, re.I).group(1)
self.correctCaptcha()
break
else:
- self.logInfo('Wrong captcha')
self.invalidCaptcha()
- if not downloadURL:
- self.fail("No Download url retrieved/all captcha attempts failed")
-
- self.download(downloadURL, disposition=True)
-
- def handlePremium(self):
- header = self.load(self.pyfile.url, just_header=True)
- if 'location' in header: # Direct Download ON
- dl = self.pyfile.url
- else: # Direct Download OFF
- html = self.load(self.pyfile.url)
- m = re.search(self.LINK_PATTERN, html)
- if m is None:
- self.parseError("Unable to detect direct link, try to enable 'Direct download' in your user settings")
- dl = 'http://filer.net' + m.group(1)
- self.logDebug('Direct link: ' + dl)
- self.download(dl, disposition=True)
+ def downloadLink(self, link):
+ if link and isinstance(link, basestring):
+ self.download(urljoin("http://filer.net/", link), disposition=True)
getInfo = create_getInfo(FilerNet)
diff --git a/module/plugins/hoster/FilerioCom.py b/module/plugins/hoster/FilerioCom.py
index 72c8c6c1c..db81f5b16 100644
--- a/module/plugins/hoster/FilerioCom.py
+++ b/module/plugins/hoster/FilerioCom.py
@@ -1,24 +1,25 @@
# -*- coding: utf-8 -*-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class FilerioCom(XFileSharingPro):
- __name__ = "FilerioCom"
- __type__ = "hoster"
+class FilerioCom(XFSHoster):
+ __name__ = "FilerioCom"
+ __type__ = "hoster"
+ __version__ = "0.07"
+
__pattern__ = r'http://(?:www\.)?(filerio\.(in|com)|filekeen\.com)/\w{12}'
- __version__ = "0.02"
+
__description__ = """FileRio.in hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- HOSTER_NAME = "filerio.in"
+ HOSTER_DOMAIN = "filerio.in"
- OFFLINE_PATTERN = r'<b>&quot;File Not Found&quot;</b>|File has been removed due to Copyright Claim'
- FILE_URL_REPLACEMENTS = [(r'http://.*?/', 'http://filerio.in/')]
+ URL_REPLACEMENTS = [(r'filekeen\.com', "filerio.in")]
- def setup(self):
- self.resumeDownload = self.multiDL = self.premium
+ OFFLINE_PATTERN = r'>&quot;File Not Found|File has been removed'
getInfo = create_getInfo(FilerioCom)
diff --git a/module/plugins/hoster/FilesMailRu.py b/module/plugins/hoster/FilesMailRu.py
index eda3a1714..9b39d818f 100644
--- a/module/plugins/hoster/FilesMailRu.py
+++ b/module/plugins/hoster/FilesMailRu.py
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
import re
-from module.plugins.Hoster import Hoster
+
from module.network.RequestFactory import getURL
+from module.plugins.Hoster import Hoster
from module.plugins.Plugin import chunks
@@ -10,15 +11,15 @@ def getInfo(urls):
result = []
for chunk in chunks(urls, 10):
for url in chunk:
- src = getURL(url)
- if r'<div class="errorMessage mb10">' in src:
+ html = getURL(url)
+ if r'<div class="errorMessage mb10">' in html:
result.append((url, 0, 1, url))
- elif r'Page cannot be displayed' in src:
+ elif r'Page cannot be displayed' in html:
result.append((url, 0, 1, url))
else:
try:
url_pattern = '<a href="(.+?)" onclick="return Act\(this\, \'dlink\'\, event\)">(.+?)</a>'
- file_name = re.search(url_pattern, src).group(0).split(', event)">')[1].split('</a>')[0]
+ file_name = re.search(url_pattern, html).group(0).split(', event)">')[1].split('</a>')[0]
result.append((file_name, 0, 2, url))
except:
pass
@@ -29,18 +30,22 @@ def getInfo(urls):
class FilesMailRu(Hoster):
- __name__ = "FilesMailRu"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?files\.mail\.ru/.*'
+ __name__ = "FilesMailRu"
+ __type__ = "hoster"
__version__ = "0.31"
+
+ __pattern__ = r'http://(?:www\.)?files\.mail\.ru/.+'
+
__description__ = """Files.mail.ru hoster plugin"""
- __author_name__ = "oZiRiz"
- __author_mail__ = "ich@oziriz.de"
+ __license__ = "GPLv3"
+ __authors__ = [("oZiRiz", "ich@oziriz.de")]
+
def setup(self):
if not self.account:
self.multiDL = False
+
def process(self, pyfile):
self.html = self.load(pyfile.url)
self.url_pattern = '<a href="(.+?)" onclick="return Act\(this\, \'dlink\'\, event\)">(.+?)</a>'
@@ -64,27 +69,31 @@ class FilesMailRu(Hoster):
self.download(self.getFileUrl())
self.myPostProcess()
+
def prepare(self):
"""You have to wait some seconds. Otherwise you will get a 40Byte HTML Page instead of the file you expected"""
self.setWait(10)
self.wait()
return True
+
def getFileUrl(self):
"""gives you the URL to the file. Extracted from the Files.mail.ru HTML-page stored in self.html"""
return re.search(self.url_pattern, self.html).group(0).split('<a href="')[1].split('" onclick="return Act')[0]
+
def getFileName(self):
"""gives you the Name for each file. Also extracted from the HTML-Page"""
return re.search(self.url_pattern, self.html).group(0).split(', event)">')[1].split('</a>')[0]
+
def myPostProcess(self):
# searches the file for HTMl-Code. Sometimes the Redirect
# doesn't work (maybe a curl Problem) and you get only a small
# HTML file and the Download is marked as "finished"
# then the download will be restarted. It's only bad for these
# who want download a HTML-File (it's one in a million ;-) )
- #
+ #
# The maximum UploadSize allowed on files.mail.ru at the moment is 100MB
# so i set it to check every download because sometimes there are downloads
# that contain the HTML-Text and 60MB ZEROs after that in a xyzfile.part1.rar file
diff --git a/module/plugins/hoster/FileserveCom.py b/module/plugins/hoster/FileserveCom.py
index 52f39bab8..52a071b52 100644
--- a/module/plugins/hoster/FileserveCom.py
+++ b/module/plugins/hoster/FileserveCom.py
@@ -1,37 +1,21 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from module.network.RequestFactory import getURL
from module.common.json_layer import json_loads
-from module.plugins.internal.CaptchaService import ReCaptcha
-from module.utils import parseFileSize
-
+from module.network.RequestFactory import getURL
from module.plugins.Hoster import Hoster
from module.plugins.Plugin import chunks
-from module.plugins.hoster.UnrestrictLi import secondsToMidnight
+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.DOTALL):
+ for li in re.finditer(plugin.LINKCHECK_TR, html, re.S):
try:
cols = re.findall(plugin.LINKCHECK_TD, li.group(1))
if cols:
@@ -47,34 +31,40 @@ def checkFile(plugin, urls):
class FileserveCom(Hoster):
- __name__ = "FileserveCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?fileserve\.com/file/(?P<id>[^/]+).*'
- __version__ = "0.52"
+ __name__ = "FileserveCom"
+ __type__ = "hoster"
+ __version__ = "0.53"
+
+ __pattern__ = r'http://(?:www\.)?fileserve\.com/file/(?P<ID>[^/]+)'
+
__description__ = """Fileserve.com hoster plugin"""
- __author_name__ = ("jeix", "mkaay", "Paul King", "zoidberg")
- __author_mail__ = ("jeix@hasnomail.de", "mkaay@mkaay.de", "", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de"),
+ ("mkaay", "mkaay@mkaay.de"),
+ ("Paul King", None),
+ ("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_TR = r'<tr>\s*(<td>http://www\.fileserve\.com/file/.*?)</tr>'
LINKCHECK_TD = r'<td>(?:<[^>]*>|&nbsp;)*([^<]*)'
- CAPTCHA_KEY_PATTERN = r"var reCAPTCHA_publickey='(?P<key>[^']+)'"
+ 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>'
+ NOT_LOGGED_IN_PATTERN = r'<form (name="loginDialogBoxForm"|id="login_form")|<li><a href="/login\.php">Login</a></li>'
- # shares code with FilejungleCom and UploadstationCom
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.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:
@@ -86,6 +76,7 @@ class FileserveCom(Hoster):
else:
self.handleFree()
+
def handleFree(self):
self.html = self.load(self.url)
action = self.load(self.url, post={"checkDownload": "check"}, decode=True)
@@ -100,11 +91,11 @@ class FileserveCom(Hoster):
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")
+ self.logWarning(_("Parallel download error, now waiting 60s"))
+ self.retry(wait_time=60, reason=_("parallelDownload"))
else:
- self.fail("Download check returned %s" % action['fail'])
+ self.fail(_("Download check returned: %s") % action['fail'])
elif "success" in action:
if action['success'] == "showCaptcha":
@@ -114,13 +105,13 @@ class FileserveCom(Hoster):
self.doTimmer()
else:
- self.fail("Unknown server response")
+ self.error(_("Unknown server response"))
# show download link
- response = self.load(self.url, post={"downloadLink": "show"}, decode=True)
- self.logDebug("show downloadLink response : %s" % response)
- if "fail" in response:
- self.fail("Couldn't retrieve download url")
+ 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"})
@@ -136,50 +127,51 @@ class FileserveCom(Hoster):
elif check == "wait":
self.doLongWait(self.lastCheck)
elif check == "limit":
- self.logWarning("Download limited reached for today")
+ 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):
- response = self.load(self.url, post={"downloadLink": "wait"}, decode=True)
- self.logDebug("wait response : %s" % response[:80])
+ res = self.load(self.url, post={"downloadLink": "wait"}, decode=True)
+ self.logDebug("Wait response: %s" % res[:80])
- if "fail" in response:
- self.fail("Failed getting wait time")
+ if "fail" in res:
+ self.fail(_("Failed getting wait time"))
if self.__name__ == "FilejungleCom":
- m = re.search(r'"waitTime":(\d+)', response)
+ m = re.search(r'"waitTime":(\d+)', res)
if m is None:
- self.fail("Cannot get wait time")
+ self.fail(_("Cannot get wait time"))
wait_time = int(m.group(1))
else:
- wait_time = int(response) + 3
+ 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("key")
+ captcha_key = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group(1)
recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- challenge, code = recaptcha.challenge(captcha_key)
-
- response = json_loads(self.load(self.URLS[2],
- post={'recaptcha_challenge_field': challenge,
- 'recaptcha_response_field': code,
- 'recaptcha_shortencode_field': self.file_id}))
- self.logDebug("reCaptcha response : %s" % response)
- if not response['success']:
+ for _i in xrange(5):
+ challenge, response = 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")
+ 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
@@ -187,27 +179,28 @@ class FileserveCom(Hoster):
self.wait()
self.retry()
+
def handlePremium(self):
premium_url = None
if self.__name__ == "FileserveCom":
#try api download
- response = 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 response:
- response = json_loads(response)
- if response['error_code'] == "302":
- premium_url = response['next']
- elif response['error_code'] in ["305", "500"]:
+ 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 response['error_code'] in ["403", "605"]:
+ elif res['error_code'] in ["403", "605"]:
self.resetAccount()
- elif response['error_code'] in ["606", "607", "608"]:
+ elif res['error_code'] in ["606", "607", "608"]:
self.offline()
else:
- self.logError(response['error_code'], response['error_message'])
+ self.logError(res['error_code'], res['error_message'])
self.download(premium_url or self.pyfile.url)
@@ -216,7 +209,7 @@ class FileserveCom(Hoster):
if check == "login":
self.account.relogin(self.user)
- self.retry(reason=_("Not logged in."))
+ self.retry(reason=_("Not logged in"))
def getInfo(urls):
diff --git a/module/plugins/hoster/FileshareInUa.py b/module/plugins/hoster/FileshareInUa.py
index 7c8c6f8ff..08e10dccb 100644
--- a/module/plugins/hoster/FileshareInUa.py
+++ b/module/plugins/hoster/FileshareInUa.py
@@ -1,79 +1,18 @@
# -*- coding: utf-8 -*-
-import re
-from module.plugins.Hoster import Hoster
-from module.network.RequestFactory import getURL
-from module.utils import parseFileSize
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-class FileshareInUa(Hoster):
- __name__ = "FileshareInUa"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?fileshare.in.ua/[A-Za-z0-9]+'
- __version__ = "0.01"
- __description__ = """Fileshare.in.ua hoster plugin"""
- __author_name__ = "fwannmacher"
- __author_mail__ = "felipe@warhammerproject.com"
-
- PATTERN_FILENAME = r'<h3 class="b-filename">(.*?)</h3>'
- PATTERN_FILESIZE = r'<b class="b-filesize">(.*?)</b>'
- PATTERN_OFFLINE = r"This file doesn't exist, or has been removed."
-
- def setup(self):
- self.resumeDownload = self.multiDL = True
-
- def process(self, pyfile):
- self.pyfile = pyfile
- self.html = self.load(pyfile.url, decode=True)
-
- if not self._checkOnline():
- self.offline()
-
- pyfile.name = self._getName()
-
- link = self._getLink()
-
- if not link.startswith('http://'):
- link = "http://fileshare.in.ua" + link
-
- self.download(link)
+class FileshareInUa(DeadHoster):
+ __name__ = "FileshareInUa"
+ __type__ = "hoster"
+ __version__ = "0.02"
- def _checkOnline(self):
- if re.search(self.PATTERN_OFFLINE, self.html):
- return False
- else:
- return True
+ __pattern__ = r'https?://(?:www\.)?fileshare\.in\.ua/\w{7}'
- def _getName(self):
- name = re.search(self.PATTERN_FILENAME, self.html)
- if name is None:
- self.fail("%s: Plugin broken." % self.__name__)
-
- return name.group(1)
-
- def _getLink(self):
- return re.search("<a href=\"(/get/.+)\" class=\"b-button m-blue m-big\" >", self.html).group(1)
-
-
-def getInfo(urls):
- result = []
-
- for url in urls:
- html = getURL(url)
-
- if re.search(FileshareInUa.PATTERN_OFFLINE, html):
- result.append((url, 0, 1, url))
- else:
- name = re.search(FileshareInUa.PATTERN_FILENAME, html)
-
- if name is None:
- result.append((url, 0, 1, url))
- continue
-
- name = name.group(1)
- size = re.search(FileshareInUa.PATTERN_FILESIZE, html)
- size = parseFileSize(size.group(1))
+ __description__ = """Fileshare.in.ua hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("fwannmacher", "felipe@warhammerproject.com")]
- result.append((name, size, 3, url))
- yield result
+getInfo = create_getInfo(FileshareInUa)
diff --git a/module/plugins/hoster/FilesonicCom.py b/module/plugins/hoster/FilesonicCom.py
new file mode 100644
index 000000000..8bfa0fa2e
--- /dev/null
+++ b/module/plugins/hoster/FilesonicCom.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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", None)]
+
+
+getInfo = create_getInfo(FilesonicCom)
diff --git a/module/plugins/hoster/FilezyNet.py b/module/plugins/hoster/FilezyNet.py
index c9d603939..4197a2858 100644
--- a/module/plugins/hoster/FilezyNet.py
+++ b/module/plugins/hoster/FilezyNet.py
@@ -1,36 +1,18 @@
# -*- coding: utf-8 -*-
-import re
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-class FilezyNet(XFileSharingPro):
- __name__ = "FilezyNet"
- __type__ = "hoster"
- __version__ = "0.1"
- __pattern__ = r'http://(?:www\.)?filezy.net/.*/.*.html'
- __description__ = """Filezy.net hoster plugin"""
-
- HOSTER_NAME = "filezy.net"
-
- FILE_SIZE_PATTERN = r'<span class="plansize">(?P<S>[0-9.]+) (?P<U>[kKMG])i?B</span>'
- WAIT_PATTERN = r'<div id="countdown_str" class="seconds">\n<!--Wait--> <span id=".*?">(\d+)</span>'
- DOWNLOAD_JS_PATTERN = r"<script type='text/javascript'>eval(.*)"
+class FilezyNet(DeadHoster):
+ __name__ = "FilezyNet"
+ __type__ = "hoster"
+ __version__ = "0.20"
- def setup(self):
- self.resumeDownload = True
- self.multiDL = self.premium
+ __pattern__ = r'http://(?:www\.)?filezy\.net/\w{12}'
- def getDownloadLink(self):
- self.logDebug("Getting download link")
-
- data = self.getPostParameters()
- self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True)
-
- obfuscated_js = re.search(self.DOWNLOAD_JS_PATTERN, self.html)
- dl_file_now = self.js.eval(obfuscated_js.group(1))
- link = re.search(self.LINK_PATTERN, dl_file_now)
- return link.group(1)
+ __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
index 6a77ded55..0e3a4e847 100644
--- a/module/plugins/hoster/FiredriveCom.py
+++ b/module/plugins/hoster/FiredriveCom.py
@@ -1,63 +1,18 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-import re
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+class FiredriveCom(DeadHoster):
+ __name__ = "FiredriveCom"
+ __type__ = "hoster"
+ __version__ = "0.05"
-class FiredriveCom(SimpleHoster):
- __name__ = "FiredriveCom"
- __type__ = "hoster"
__pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/(mobile/)?(file|embed)/(?P<ID>\w+)'
- __version__ = "0.03"
- __description__ = """Firedrive.com hoster plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
-
- FILE_NAME_PATTERN = r'<b>Name:</b> (?P<N>.+) <br>'
- FILE_SIZE_PATTERN = r'<b>Size:</b> (?P<S>[\d.]+) (?P<U>[a-zA-Z]+) <br>'
- OFFLINE_PATTERN = r'class="sad_face_image"|>No such page here.<'
- TEMP_OFFLINE_PATTERN = r'>(File Temporarily Unavailable|Server Error. Try again later)'
-
- FILE_URL_REPLACEMENTS = [(__pattern__, r'http://www.firedrive.com/file/\g<ID>')]
-
- LINK_PATTERN = r'<a href="(https?://dl\.firedrive\.com/\?key=.+?)"'
-
- def setup(self):
- self.multiDL = self.resumeDownload = True
- self.chunkLimit = -1
-
- def handleFree(self):
- link = self._getLink()
- self.logDebug("Direct link: " + link)
- self.download(link, disposition=True)
-
- def _getLink(self):
- f = re.search(self.LINK_PATTERN, self.html)
- if f:
- return f.group(1)
- else:
- self.html = self.load(self.pyfile.url, post={"confirm": re.search(r'name="confirm" value="(.+?)"', self.html).group(1)})
- f = re.search(self.LINK_PATTERN, self.html)
- if f:
- return f.group(1)
- else:
- self.parseError("Direct download link not found")
+ __description__ = """Firedrive.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
getInfo = create_getInfo(FiredriveCom)
diff --git a/module/plugins/hoster/FlyFilesNet.py b/module/plugins/hoster/FlyFilesNet.py
index 1d7ba4fcc..49705958d 100644
--- a/module/plugins/hoster/FlyFilesNet.py
+++ b/module/plugins/hoster/FlyFilesNet.py
@@ -1,24 +1,31 @@
# -*- coding: utf-8 -*-
import re
-import urllib
-from module.plugins.internal.SimpleHoster import SimpleHoster
+from urllib import unquote
+
from module.network.RequestFactory import getURL
+from module.plugins.internal.SimpleHoster import SimpleHoster
class FlyFilesNet(SimpleHoster):
- __name__ = "FlyFilesNet"
- __version__ = "0.1"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?flyfiles\.net/.*'
+ __name__ = "FlyFilesNet"
+ __type__ = "hoster"
+ __version__ = "0.10"
+
+ __pattern__ = r'http://(?:www\.)?flyfiles\.net/.+'
+
+ __description__ = """FlyFiles.net hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = []
SESSION_PATTERN = r'flyfiles\.net/(.*)/.*'
- FILE_NAME_PATTERN = r'flyfiles\.net/.*/(.*)'
+ NAME_PATTERN = r'flyfiles\.net/.*/(.*)'
+
def process(self, pyfile):
- name = re.search(self.FILE_NAME_PATTERN, pyfile.url).group(1)
- pyfile.name = urllib.unquote_plus(name)
+ name = re.search(self.NAME_PATTERN, pyfile.url).group(1)
+ pyfile.name = unquote_plus(name)
session = re.search(self.SESSION_PATTERN, pyfile.url).group(1)
@@ -29,11 +36,10 @@ class FlyFilesNet(SimpleHoster):
self.logDebug("Parsed URL: %s" % parsed_url)
if parsed_url == '#downlink|' or parsed_url == "#downlink|#":
- self.logWarning("Could not get the download URL. Please wait 10 minutes.")
+ self.logWarning(_("Could not get the download URL. Please wait 10 minutes"))
self.wait(10 * 60, True)
self.retry()
download_url = parsed_url.replace('#downlink|', '')
- self.logDebug("Download URL: %s" % download_url)
self.download(download_url)
diff --git a/module/plugins/hoster/FourSharedCom.py b/module/plugins/hoster/FourSharedCom.py
index 6a32b5325..0406df0c4 100644
--- a/module/plugins/hoster/FourSharedCom.py
+++ b/module/plugins/hoster/FourSharedCom.py
@@ -6,20 +6,24 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class FourSharedCom(SimpleHoster):
- __name__ = "FourSharedCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?4shared(\-china)?\.com/(account/)?(download|get|file|document|photo|video|audio|mp3|office|rar|zip|archive|music)/.+?/.*'
- __version__ = "0.29"
+ __name__ = "FourSharedCom"
+ __type__ = "hoster"
+ __version__ = "0.30"
+
+ __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"""
- __author_name__ = ("jeix", "zoidberg")
- __author_mail__ = ("jeix@hasnomail.de", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_NAME_PATTERN = r'<meta name="title" content="(?P<N>.+?)"'
- FILE_SIZE_PATTERN = r'<span title="Size: (?P<S>[0-9,.]+) (?P<U>[kKMG])i?B">'
+ 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.'
- FILE_NAME_REPLACEMENTS = [(r"&#(\d+).", lambda m: unichr(int(m.group(1))))]
- FILE_SIZE_REPLACEMENTS = [(",", "")]
+ NAME_REPLACEMENTS = [(r"&#(\d+).", lambda m: unichr(int(m.group(1))))]
+ SIZE_REPLACEMENTS = [(",", "")]
DOWNLOAD_URL_PATTERN = r'name="d3link" value="(.*?)"'
DOWNLOAD_BUTTON_PATTERN = r'id="btnLink" href="(.*?)"'
@@ -28,7 +32,7 @@ class FourSharedCom(SimpleHoster):
def handleFree(self):
if not self.account:
- self.fail("User not logged in")
+ self.fail(_("User not logged in"))
m = re.search(self.DOWNLOAD_BUTTON_PATTERN, self.html)
if m:
@@ -40,13 +44,13 @@ class FourSharedCom(SimpleHoster):
m = re.search(self.DOWNLOAD_URL_PATTERN, self.html)
if m is None:
- self.parseError('Download link')
+ self.error(_("Download link"))
link = m.group(1)
try:
m = re.search(self.FID_PATTERN, self.html)
- response = self.load('http://www.4shared.com/web/d2/getFreeDownloadLimitInfo?fileId=%s' % m.group(1))
- self.logDebug(response)
+ res = self.load('http://www.4shared.com/web/d2/getFreeDownloadLimitInfo?fileId=%s' % m.group(1))
+ self.logDebug(res)
except:
pass
diff --git a/module/plugins/hoster/FreakshareCom.py b/module/plugins/hoster/FreakshareCom.py
index ff1056c9f..2238f07ef 100644
--- a/module/plugins/hoster/FreakshareCom.py
+++ b/module/plugins/hoster/FreakshareCom.py
@@ -3,23 +3,30 @@
import re
from module.plugins.Hoster import Hoster
-from module.plugins.hoster.UnrestrictLi import secondsToMidnight
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import secondsToMidnight
class FreakshareCom(Hoster):
- __name__ = "FreakshareCom"
- __type__ = "hoster"
+ __name__ = "FreakshareCom"
+ __type__ = "hoster"
+ __version__ = "0.40"
+
__pattern__ = r'http://(?:www\.)?freakshare\.(net|com)/files/\S*?/'
- __version__ = "0.39"
+
__description__ = """Freakshare.com hoster plugin"""
- __author_name__ = ("sitacuisses", "spoob", "mkaay", "Toilal")
- __author_mail__ = ("sitacuisses@yahoo.de", "spoob@pyload.org", "mkaay@mkaay.de", "toilal.dev@gmail.com")
+ __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
@@ -43,24 +50,23 @@ class FreakshareCom(Hoster):
"downloadserver": "No Downloadserver. Please try again later!"})
if check == "bad":
- self.fail("Bad Try.")
+ self.fail(_("Bad Try"))
elif check == "paralell":
self.setWait(300, True)
self.wait()
self.retry()
elif check == "empty":
- self.fail("File not downloadable")
+ self.fail(_("File not downloadable"))
elif check == "wrong_captcha":
self.invalidCaptcha()
self.retry()
elif check == "downloadserver":
- self.retry(5, 15 * 60, "No Download server")
+ self.retry(5, 15 * 60, _("No Download server"))
+
def prepare(self):
pyfile = self.pyfile
- self.wantReconnect = False
-
self.download_html()
if not self.file_exists():
@@ -75,10 +81,12 @@ class FreakshareCom(Hoster):
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
"""
@@ -91,6 +99,7 @@ class FreakshareCom(Hoster):
else:
self.offline()
+
def get_file_name(self):
if not self.html:
self.download_html()
@@ -104,6 +113,7 @@ class FreakshareCom(Hoster):
else:
return self.pyfile.url
+
def get_file_size(self):
size = 0
if not self.html:
@@ -118,6 +128,7 @@ class FreakshareCom(Hoster):
return size
+
def get_waiting_time(self):
if not self.html:
self.download_html()
@@ -126,12 +137,13 @@ class FreakshareCom(Hoster):
self.wantReconnect = True
return secondsToMidnight(gmt=2)
- timestring = re.search('\s*var\s(?:downloadWait|time)\s=\s(\d*)[.\d]*;', self.html)
+ timestring = re.search('\s*var\s(?:downloadWait|time)\s=\s(\d*)[\d.]*;', self.html)
if timestring:
- return int(timestring.group(1)) + 1 # add 1 sec as tenths of seconds are cut off
+ return int(timestring.group(1))
else:
return 60
+
def file_exists(self):
""" returns True or False
"""
@@ -142,6 +154,7 @@ class FreakshareCom(Hoster):
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
@@ -150,21 +163,14 @@ class FreakshareCom(Hoster):
herewego = self.load(self.pyfile.url, None, request_options) # the actual download-Page
- # comment this in, when it doesnt work
- # with open("DUMP__FS_.HTML", "w") as fp:
- # fp.write(herewego)
-
to_sort = re.findall(r"<input\stype=\".*?\"\svalue=\"(\S*?)\".*?name=\"(\S*?)\"\s.*?\/>", herewego)
request_options = dict((n, v) for (v, n) in to_sort)
- # comment this in, when it doesnt work as well
- #print "\n\n%s\n\n" % ";".join(["%s=%s" % x for x in to_sort])
-
- challenge = re.search(r"http://api\.recaptcha\.net/challenge\?k=([0-9A-Za-z]+)", herewego)
+ 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_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
index ef07ebaff..80d0b8515 100644
--- a/module/plugins/hoster/FreeWayMe.py
+++ b/module/plugins/hoster/FreeWayMe.py
@@ -1,47 +1,34 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+class FreeWayMe(MultiHoster):
+ __name__ = "FreeWayMe"
+ __type__ = "hoster"
+ __version__ = "0.14"
-from module.plugins.Hoster import Hoster
+ __pattern__ = r'https://(?:www\.)?free-way\.me/.+'
-
-class FreeWayMe(Hoster):
- __name__ = "FreeWayMe"
- __version__ = "0.11"
- __type__ = "hoster"
- __pattern__ = r'https://(?:www\.)?free-way.me/.*'
__description__ = """FreeWayMe hoster plugin"""
- __author_name__ = "Nicolas Giese"
- __author_mail__ = "james@free-way.me"
+ __license__ = "GPLv3"
+ __authors__ = [("Nicolas Giese", "james@free-way.me")]
+
def setup(self):
self.resumeDownload = False
- self.chunkLimit = 1
- self.multiDL = self.premium
-
- def process(self, pyfile):
- if not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "FreeWayMe")
- self.fail("No FreeWay account provided")
+ self.multiDL = self.premium
+ self.chunkLimit = 1
- self.logDebug("Old URL: %s" % pyfile.url)
- (user, data) = self.account.selectAccount()
+ def handlePremium(self):
+ user, data = self.account.selectAccount()
+ self.link = True
self.download(
"https://www.free-way.me/load.php",
- get={"multiget": 7, "url": pyfile.url, "user": user, "pw": self.account.getpw(user), "json": ""},
+ get={"multiget": 7, "url": self.pyfile.url, "user": user, "pw": self.account.getpw(user), "json": ""},
disposition=True)
+
+
+getInfo = create_getInfo(FreeWayMe)
diff --git a/module/plugins/hoster/FreevideoCz.py b/module/plugins/hoster/FreevideoCz.py
index 0945f173a..e56d1a299 100644
--- a/module/plugins/hoster/FreevideoCz.py
+++ b/module/plugins/hoster/FreevideoCz.py
@@ -4,15 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class FreevideoCz(DeadHoster):
- __name__ = "FreevideoCz"
- __version__ = "0.3"
- __type__ = "hoster"
+ __name__ = "FreevideoCz"
+ __type__ = "hoster"
+ __version__ = "0.30"
__pattern__ = r'http://(?:www\.)?freevideo\.cz/vase-videa/.+'
__description__ = """Freevideo.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
getInfo = create_getInfo(FreevideoCz) \ No newline at end of file
diff --git a/module/plugins/hoster/FshareVn.py b/module/plugins/hoster/FshareVn.py
index 0b728495a..a3f9703df 100644
--- a/module/plugins/hoster/FshareVn.py
+++ b/module/plugins/hoster/FshareVn.py
@@ -1,22 +1,20 @@
# -*- coding: utf-8 -*-
import re
+
from time import strptime, mktime, gmtime
-from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo
from module.network.RequestFactory import getURL
+from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo
def getInfo(urls):
for url in urls:
- html = getURL('http://www.fshare.vn/check_link.php', post={
- "action": "check_link",
- "arrlinks": url
- }, decode=True)
+ html = getURL("http://www.fshare.vn/check_link.php",
+ post={'action': "check_link", 'arrlinks': url},
+ decode=True)
- file_info = parseFileInfo(FshareVn, url, html)
-
- yield file_info
+ yield parseFileInfo(FshareVn, url, html)
def doubleDecode(m):
@@ -24,18 +22,21 @@ def doubleDecode(m):
class FshareVn(SimpleHoster):
- __name__ = "FshareVn"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?fshare.vn/file/.*'
- __version__ = "0.16"
+ __name__ = "FshareVn"
+ __type__ = "hoster"
+ __version__ = "0.18"
+
+ __pattern__ = r'http://(?:www\.)?fshare\.vn/file/.+'
+
__description__ = """FshareVn hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_INFO_PATTERN = r'<p>(?P<N>[^<]+)<\\/p>[\\trn\s]*<p>(?P<S>[0-9,.]+)\s*(?P<U>[kKMG])i?B<\\/p>'
+ INFO_PATTERN = r'<p>(?P<N>[^<]+)<\\/p>[\\trn\s]*<p>(?P<S>[\d.,]+)\s*(?P<U>[\w^_]+)<\\/p>'
OFFLINE_PATTERN = r'<div class=\\"f_left file_w\\"|<\\/p>\\t\\t\\t\\t\\r\\n\\t\\t<p><\\/p>\\t\\t\\r\\n\\t\\t<p>0 KB<\\/p>'
- FILE_NAME_REPLACEMENTS = [("(.*)", doubleDecode)]
+ NAME_REPLACEMENTS = [("(.*)", doubleDecode)]
LINK_PATTERN = r'action="(http://download.*?)[#"]'
WAIT_PATTERN = ur'Lượt tải xuống kế tiếp là:\s*(.*?)\s*<'
@@ -54,6 +55,7 @@ class FshareVn(SimpleHoster):
self.handleFree()
self.checkDownloadedFile()
+
def handleFree(self):
self.html = self.load(self.pyfile.url, decode=True)
@@ -63,16 +65,21 @@ class FshareVn(SimpleHoster):
self.url = self.pyfile.url + action
if not inputs:
- self.parseError('FORM')
+ self.error(_("No FORM"))
+
elif 'link_file_pwd_dl' in inputs:
- for password in self.getPassword().splitlines():
- self.logInfo('Password protected link, trying "%s"' % password)
+ password = self.getPassword()
+
+ if password:
+ self.logInfo(_("Password protected link, trying ") + password)
inputs['link_file_pwd_dl'] = password
self.html = self.load(self.url, post=inputs, decode=True)
- if not 'name="link_file_pwd_dl"' in self.html:
- break
+
+ if 'name="link_file_pwd_dl"' in self.html:
+ self.fail(_("Incorrect password"))
else:
- self.fail("No or incorrect password")
+ self.fail(_("No password found"))
+
else:
self.html = self.load(self.url, post=inputs, decode=True)
@@ -83,29 +90,35 @@ class FshareVn(SimpleHoster):
m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.parseError('FREE DL URL')
+ self.error(_("LINK_PATTERN not found"))
self.url = m.group(1)
self.logDebug("FREE DL URL: %s" % self.url)
self.wait()
self.download(self.url)
+
def handlePremium(self):
self.download(self.pyfile.url)
+
def checkErrors(self):
if '/error.php?' in self.req.lastEffectiveURL or u"Liên kết bạn chọn khÃŽng tồn" in self.html:
self.offline()
m = re.search(self.WAIT_PATTERN, self.html)
if m:
- self.logInfo("Wait until %s ICT" % m.group(1))
+ self.logInfo(_("Wait until %s ICT") % m.group(1))
wait_until = mktime(strptime(m.group(1), "%d/%m/%Y %H:%M"))
self.wait(wait_until - mktime(gmtime()) - 7 * 60 * 60, True)
self.retry()
elif '<ul class="message-error">' in self.html:
- self.logError("Unknown error occured or wait time not parsed")
- self.retry(30, 2 * 60, "Unknown error")
+ msg = "Unknown error occured or wait time not parsed"
+ self.logError(msg)
+ self.retry(30, 2 * 60, msg)
+
+ self.info.pop('error', None)
+
def checkDownloadedFile(self):
# check download
@@ -114,4 +127,4 @@ class FshareVn(SimpleHoster):
})
if check == "not_found":
- self.fail("File not m on server")
+ self.fail(_("File not m on server"))
diff --git a/module/plugins/hoster/Ftp.py b/module/plugins/hoster/Ftp.py
index 07169ff2e..c6ad68e49 100644
--- a/module/plugins/hoster/Ftp.py
+++ b/module/plugins/hoster/Ftp.py
@@ -1,40 +1,33 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-from urlparse import urlparse
-from urllib import quote, unquote
import pycurl
import re
+from urllib import quote, unquote
+from urlparse import urlparse
+
from module.plugins.Hoster import Hoster
class Ftp(Hoster):
- __name__ = "Ftp"
- __version__ = "0.41"
- __pattern__ = r'(ftps?|sftp)://(.*?:.*?@)?.*?/.*' # ftp://user:password@ftp.server.org/path/to/file
- __type__ = "hoster"
+ __name__ = "Ftp"
+ __type__ = "hoster"
+ __version__ = "0.44"
+
+ __pattern__ = r'(?:ftps?|sftp)://([\w.-]+(:[\w.-]+)?@)?[\w.-]+(:\d+)?/.+'
+
__description__ = """Download from ftp directory"""
- __author_name__ = ("jeix", "mkaay", "zoidberg")
- __author_mail__ = ("jeix@hasnomail.com", "mkaay@mkaay.de", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.com"),
+ ("mkaay", "mkaay@mkaay.de"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
def setup(self):
self.chunkLimit = -1
self.resumeDownload = True
+
def process(self, pyfile):
parsed_url = urlparse(pyfile.url)
netloc = parsed_url.netloc
@@ -52,35 +45,34 @@ class Ftp(Hoster):
self.logDebug("Logging on to %s" % netloc)
self.req.addAuth(self.account.accounts[netloc]['password'])
else:
- for pwd in pyfile.package().password.splitlines():
- if ":" in pwd:
- self.req.addAuth(pwd.strip())
- break
+ pwd = self.getPassword()
+ if ':' in pwd:
+ self.req.addAuth(pwd)
self.req.http.c.setopt(pycurl.NOBODY, 1)
try:
- response = self.load(pyfile.url)
+ res = self.load(pyfile.url)
except pycurl.error, e:
- self.fail("Error %d: %s" % e.args)
+ self.fail(_("Error %d: %s") % e.args)
self.req.http.c.setopt(pycurl.NOBODY, 0)
self.logDebug(self.req.http.header)
- m = re.search(r"Content-Length:\s*(\d+)", response)
+ m = re.search(r"Content-Length:\s*(\d+)", res)
if m:
pyfile.size = int(m.group(1))
self.download(pyfile.url)
else:
- #Naive ftp directory listing
+ #Naive ftp directory listing
if re.search(r'^25\d.*?"', self.req.http.header, re.M):
pyfile.url = pyfile.url.rstrip('/')
pkgname = "/".join(pyfile.package().name, urlparse(pyfile.url).path.rpartition('/')[2])
pyfile.url += '/'
self.req.http.c.setopt(48, 1) # CURLOPT_DIRLISTONLY
- response = self.load(pyfile.url, decode=False)
- links = [pyfile.url + quote(x) for x in response.splitlines()]
+ res = self.load(pyfile.url, decode=False)
+ links = [pyfile.url + quote(x) for x in res.splitlines()]
self.logDebug("LINKS", links)
self.core.api.addPackage(pkgname, links)
else:
- self.fail("Unexpected server response")
+ self.fail(_("Unexpected server response"))
diff --git a/module/plugins/hoster/GamefrontCom.py b/module/plugins/hoster/GamefrontCom.py
index 8e0f8565f..c68866f87 100644
--- a/module/plugins/hoster/GamefrontCom.py
+++ b/module/plugins/hoster/GamefrontCom.py
@@ -1,27 +1,34 @@
# -*- coding: utf-8 -*-
import re
-from module.plugins.Hoster import Hoster
+
from module.network.RequestFactory import getURL
+from module.plugins.Hoster import Hoster
from module.utils import parseFileSize
class GamefrontCom(Hoster):
- __name__ = "GamefrontCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?gamefront.com/files/[A-Za-z0-9]+'
+ __name__ = "GamefrontCom"
+ __type__ = "hoster"
__version__ = "0.04"
+
+ __pattern__ = r'http://(?:www\.)?gamefront\.com/files/\w+'
+
__description__ = """Gamefront.com hoster plugin"""
- __author_name__ = "fwannmacher"
- __author_mail__ = "felipe@warhammerproject.com"
+ __license__ = "GPLv3"
+ __authors__ = [("fwannmacher", "felipe@warhammerproject.com")]
+
PATTERN_FILENAME = r'<title>(.*?) | Game Front'
PATTERN_FILESIZE = r'<dt>File Size:</dt>[\n\s]*<dd>(.*?)</dd>'
- PATTERN_OFFLINE = r"This file doesn't exist, or has been removed."
+ PATTERN_OFFLINE = r'This file doesn\'t exist, or has been removed.'
+
def setup(self):
- self.resumeDownload = self.multiDL = True
- self.chunkLimit = -1
+ self.resumeDownload = True
+ self.multiDL = True
+ self.chunkLimit = -1
+
def process(self, pyfile):
self.pyfile = pyfile
@@ -39,23 +46,26 @@ class GamefrontCom(Hoster):
self.download(link)
+
def _checkOnline(self):
if re.search(self.PATTERN_OFFLINE, self.html):
return False
else:
return True
+
def _getName(self):
name = re.search(self.PATTERN_FILENAME, self.html)
if name is None:
- self.fail("%s: Plugin broken." % self.__name__)
+ self.fail(_("Plugin broken")
return name.group(1)
+
def _getLink(self):
- self.html2 = self.load("http://www.gamefront.com/" + re.search("(files/service/thankyou\\?id=[A-Za-z0-9]+)",
+ self.html2 = self.load("http://www.gamefront.com/" + re.search("(files/service/thankyou\\?id=\w+)",
self.html).group(1))
- return re.search("<a href=\"(http://media[0-9]+\.gamefront.com/.*)\">click here</a>", self.html2).group(1).replace("&amp;", "&")
+ return re.search("<a href=\"(http://media\d+\.gamefront.com/.*)\">click here</a>", self.html2).group(1).replace("&amp;", "&")
def getInfo(urls):
diff --git a/module/plugins/hoster/GigapetaCom.py b/module/plugins/hoster/GigapetaCom.py
index 9d9825cb8..37af7f216 100644
--- a/module/plugins/hoster/GigapetaCom.py
+++ b/module/plugins/hoster/GigapetaCom.py
@@ -1,41 +1,30 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from random import randint
+
from pycurl import FOLLOWLOCATION
+from random import randint
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class GigapetaCom(SimpleHoster):
- __name__ = "GigapetaCom"
- __type__ = "hoster"
+ __name__ = "GigapetaCom"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
__pattern__ = r'http://(?:www\.)?gigapeta\.com/dl/\w+'
- __version__ = "0.01"
+
__description__ = """GigaPeta.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_NAME_PATTERN = r'<img src=".*" alt="file" />-->\s*(?P<N>.*?)\s*</td>'
- FILE_SIZE_PATTERN = r'<th>\s*Size\s*</th>\s*<td>\s*(?P<S>.*?)\s*</td>'
+ 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">'
- SH_COOKIES = [(".gigapeta.com", "lang", "us")]
+ COOKIES = [("gigapeta.com", "lang", "us")]
def handleFree(self):
@@ -44,7 +33,7 @@ class GigapetaCom(SimpleHoster):
self.req.http.c.setopt(FOLLOWLOCATION, 0)
- for _ in xrange(5):
+ for _i in xrange(5):
self.checkErrors()
captcha = self.decryptCaptcha(captcha_url)
@@ -53,24 +42,26 @@ class GigapetaCom(SimpleHoster):
"captcha": captcha,
"download": "Download"})
- m = re.search(r"Location\s*:\s*(.*)", self.req.http.header, re.I)
+ m = re.search(r'Location\s*:\s*(.+)', self.req.http.header, re.I)
if m:
- download_url = m.group(1)
+ download_url = m.group(1).rstrip() #@TODO: Remove .rstrip() in 0.4.10
break
elif "Entered figures don&#96;t coincide with the picture" in self.html:
self.invalidCaptcha()
else:
- self.fail("No valid captcha code entered")
+ self.fail(_("No valid captcha code entered"))
self.req.http.c.setopt(FOLLOWLOCATION, 1)
- self.logDebug("Download URL: %s" % download_url)
self.download(download_url)
+
def checkErrors(self):
if "All threads for IP" in self.html:
- self.logDebug("Your IP is already downloading a file - wait and retry")
+ 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
index 9f06e5ca0..436d825a9 100644
--- a/module/plugins/hoster/GooIm.py
+++ b/module/plugins/hoster/GooIm.py
@@ -1,18 +1,7 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
+#
+# Test links:
+# https://goo.im/devs/liquidsmooth/3.x/codina/Nightly/LS-KK-v3.2-2014-08-01-codina.zip
import re
@@ -20,34 +9,31 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class GooIm(SimpleHoster):
- __name__ = "GooIm"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?goo\.im/.+'
- __version__ = "0.02"
+ __name__ = "GooIm"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
+ __pattern__ = r'https?://(?:www\.)?goo\.im/.+'
+
__description__ = """Goo.im hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")]
+
- FILE_NAME_PATTERN = r'<h3>Filename: (?P<N>.+)</h3>'
+ 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.chunkLimit = -1
- self.multiDL = self.resumeDownload = True
+ self.resumeDownload = True
+ self.multiDL = True
+
def handleFree(self):
- self.html = self.load(self.pyfile.url)
- m = re.search(r'MD5sum: (?P<MD5>[0-9a-z]{32})</h3>', self.html)
- if m:
- self.check_data = {"md5": m.group('MD5')}
+ url = self.pyfile.url
+ self.html = self.load(url, cookies=True)
self.wait(10)
-
- header = self.load(self.pyfile.url, just_header=True)
- if header['location']:
- self.logDebug("Direct link: " + header['location'])
- self.download(header['location'])
- else:
- self.parseError("Unable to detect direct download link")
+ self.download(url, cookies=True)
getInfo = create_getInfo(GooIm)
diff --git a/module/plugins/hoster/HellshareCz.py b/module/plugins/hoster/HellshareCz.py
index 54f931eb2..4b44cc335 100644
--- a/module/plugins/hoster/HellshareCz.py
+++ b/module/plugins/hoster/HellshareCz.py
@@ -1,57 +1,47 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class HellshareCz(SimpleHoster):
- __name__ = "HellshareCz"
- __type__ = "hoster"
- __pattern__ = r'(http://(?:www\.)?hellshare\.(?:cz|com|sk|hu|pl)/[^?]*/\d+).*'
- __version__ = "0.82"
+ __name__ = "HellshareCz"
+ __type__ = "hoster"
+ __version__ = "0.83"
+
+ __pattern__ = r'(http://(?:www\.)?hellshare\.(?:cz|com|sk|hu|pl)/[^?]*/\d+)'
+
__description__ = """Hellshare.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<h1 id="filename"[^>]*>(?P<N>[^<]+)</h1>'
- FILE_SIZE_PATTERN = r'<strong id="FileSize_master">(?P<S>[0-9.]*)&nbsp;(?P<U>[kKMG])i?B</strong>'
+
+ NAME_PATTERN = r'<h1 id="filename"[^>]*>(?P<N>[^<]+)</h1>'
+ SIZE_PATTERN = r'<strong id="FileSize_master">(?P<S>[\d.,]+)&nbsp;(?P<U>[\w^_]+)</strong>'
OFFLINE_PATTERN = r'<h1>File not found.</h1>'
SHOW_WINDOW_PATTERN = r'<a href="([^?]+/(\d+)/\?do=(fileDownloadButton|relatedFileDownloadButton-\2)-showDownloadWindow)"'
+
def setup(self):
self.resumeDownload = self.multiDL = True if self.account else False
self.chunkLimit = 1
+
def process(self, pyfile):
if not self.account:
- self.fail("User not logged in")
+ self.fail(_("User not logged in"))
pyfile.url = re.match(self.__pattern__, pyfile.url).group(1)
self.html = self.load(pyfile.url, decode=True)
self.getFileInfo()
if not self.checkTrafficLeft():
- self.fail("Not enough traffic left for user %s." % self.user)
+ self.fail(_("Not enough traffic left for user ") + self.user)
m = re.search(self.SHOW_WINDOW_PATTERN, self.html)
if m is None:
- self.parseError('SHOW WINDOW')
- self.url = "http://www.hellshare.com" + m.group(1)
- self.logDebug("DOWNLOAD URL: " + self.url)
+ self.error(_("SHOW_WINDOW_PATTERN not found"))
+ self.url = "http://www.hellshare.com" + m.group(1)
self.download(self.url)
diff --git a/module/plugins/hoster/HellspyCz.py b/module/plugins/hoster/HellspyCz.py
index 399dea818..2b9b76b8a 100644
--- a/module/plugins/hoster/HellspyCz.py
+++ b/module/plugins/hoster/HellspyCz.py
@@ -1,31 +1,18 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class HellspyCz(DeadHoster):
- __name__ = "HellspyCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(?:hellspy\.(?:cz|com|sk|hu|pl)|sciagaj.pl)(/\S+/\d+)/?.*'
+ __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"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
index 9a0947f2c..f7724faf2 100644
--- a/module/plugins/hoster/HotfileCom.py
+++ b/module/plugins/hoster/HotfileCom.py
@@ -4,13 +4,18 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class HotfileCom(DeadHoster):
- __name__ = "HotfileCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(www.)?hotfile\.com/dl/\d+/[0-9a-zA-Z]+/'
+ __name__ = "HotfileCom"
+ __type__ = "hoster"
__version__ = "0.37"
+
+ __pattern__ = r'https?://(?:www\.)?hotfile\.com/dl/\d+/\w+'
+
__description__ = """Hotfile.com hoster plugin"""
- __author_name__ = ("sitacuisses", "spoob", "mkaay", "JoKoT3")
- __author_mail__ = ("sitacuisses@yhoo.de", "spoob@pyload.org", "mkaay@mkaay.de", "jokot3@gmail.com")
+ __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
index 2375c75f8..f7221f8c5 100644
--- a/module/plugins/hoster/HugefilesNet.py
+++ b/module/plugins/hoster/HugefilesNet.py
@@ -1,37 +1,27 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-# Test links (random.bin):
-# http://hugefiles.net/prthf9ya4w6s
-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-
-
-class HugefilesNet(XFileSharingPro):
- __name__ = "HugefilesNet"
- __type__ = "hoster"
+
+import re
+
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+
+class HugefilesNet(XFSHoster):
+ __name__ = "HugefilesNet"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
__pattern__ = r'http://(?:www\.)?hugefiles\.net/\w{12}'
- __version__ = "0.01"
+
__description__ = """Hugefiles.net hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
+
+ HOSTER_DOMAIN = "hugefiles.net"
- HOSTER_NAME = "hugefiles.net"
+ SIZE_PATTERN = r'File Size:</span>\s*<span[^>]*>(?P<S>[^<]+)</span></div>'
- FILE_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
index 6e5ffac30..317a49caf 100644
--- a/module/plugins/hoster/HundredEightyUploadCom.py
+++ b/module/plugins/hoster/HundredEightyUploadCom.py
@@ -1,38 +1,24 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-# Test links (random.bin):
+#
+# Test links:
# http://180upload.com/js9qdm6kjnrs
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class HundredEightyUploadCom(XFileSharingPro):
- __name__ = "HundredEightyUploadCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?180upload\.com/(\w+).*'
- __version__ = "0.01"
+class HundredEightyUploadCom(XFSHoster):
+ __name__ = "HundredEightyUploadCom"
+ __type__ = "hoster"
+ __version__ = "0.04"
+
+ __pattern__ = r'http://(?:www\.)?180upload\.com/\w{12}'
+
__description__ = """180upload.com hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
- HOSTER_NAME = "180upload.com"
- FILE_NAME_PATTERN = r'Filename:</b></td><td nowrap>(?P<N>.+)</td></tr>-->'
- FILE_SIZE_PATTERN = r'Size:</b></td><td>(?P<S>[\d.]+) (?P<U>[A-Z]+)\s*<small>'
+ HOSTER_DOMAIN = "180upload.com"
getInfo = create_getInfo(HundredEightyUploadCom)
diff --git a/module/plugins/hoster/IFileWs.py b/module/plugins/hoster/IFileWs.py
index 35b3544a1..b4f225c4b 100644
--- a/module/plugins/hoster/IFileWs.py
+++ b/module/plugins/hoster/IFileWs.py
@@ -1,21 +1,18 @@
# -*- coding: utf-8 -*-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-class IFileWs(XFileSharingPro):
- __name__ = "IFileWs"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?ifile\.ws/\w+(/.+)?'
- __version__ = "0.01"
- __description__ = """Ifile.ws hoster plugin"""
- __author_name__ = "z00nx"
- __author_mail__ = "z00nx0@gmail.com"
+class IFileWs(DeadHoster):
+ __name__ = "IFileWs"
+ __type__ = "hoster"
+ __version__ = "0.02"
- HOSTER_NAME = "ifile.ws"
+ __pattern__ = r'http://(?:www\.)?ifile\.ws/\w{12}'
- FILE_INFO_PATTERN = r'<h1\s+style="display:inline;">(?P<N>[^<]+)</h1>\s+\[(?P<S>[^]]+)\]'
- OFFLINE_PATTERN = r'File Not Found|The file was removed by administrator'
+ __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
index 2f3c65c3b..921b64207 100644
--- a/module/plugins/hoster/IcyFilesCom.py
+++ b/module/plugins/hoster/IcyFilesCom.py
@@ -1,31 +1,18 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class IcyFilesCom(DeadHoster):
- __name__ = "IcyFilesCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?icyfiles\.com/(.*)'
+ __name__ = "IcyFilesCom"
+ __type__ = "hoster"
__version__ = "0.06"
+
+ __pattern__ = r'http://(?:www\.)?icyfiles\.com/(.+)'
+
__description__ = """IcyFiles.com hoster plugin"""
- __author_name__ = "godofdream"
- __author_mail__ = "soilfiction@gmail.com"
+ __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
index b75daf3af..2dae4cd80 100644
--- a/module/plugins/hoster/IfileIt.py
+++ b/module/plugins/hoster/IfileIt.py
@@ -1,73 +1,67 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
from module.common.json_layer import json_loads
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class IfileIt(SimpleHoster):
- __name__ = "IfileIt"
- __type__ = "hoster"
+ __name__ = "IfileIt"
+ __type__ = "hoster"
+ __version__ = "0.28"
+
__pattern__ = r'^unmatchable$'
- __version__ = "0.27"
+
__description__ = """Ifile.it"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
LINK_PATTERN = r'</span> If it doesn\'t, <a target="_blank" href="([^"]+)">'
- RECAPTCHA_KEY_PATTERN = r"var __recaptcha_public\s*=\s*'([^']+)';"
- FILE_INFO_PATTERN = r'<span style="cursor: default;[^>]*>\s*(?P<N>.*?)\s*&nbsp;\s*<strong>\s*(?P<S>[0-9.]+)\s*(?P<U>[kKMG])i?B\s*</strong>\s*</span>'
+ RECAPTCHA_PATTERN = r'var __recaptcha_public\s*=\s*\'(.+?)\''
+ INFO_PATTERN = r'<span style="cursor: default;[^>]*>\s*(?P<N>.*?)\s*&nbsp;\s*<strong>\s*(?P<S>[\d.,]+)\s*(?P<U>[\w^_]+)\s*</strong>\s*</span>'
OFFLINE_PATTERN = r'<span style="cursor: default;[^>]*>\s*&nbsp;\s*<strong>\s*</strong>\s*</span>'
TEMP_OFFLINE_PATTERN = r'<span class="msg_red">Downloading of this file is temporarily disabled</span>'
+
def handleFree(self):
- ukey = re.match(self.__pattern__, self.pyfile.url).group(1)
- json_url = 'http://ifile.it/new_download-request.json'
+ ukey = re.match(self.__pattern__, self.pyfile.url).group(1)
+ json_url = 'http://ifile.it/new_download-request.json'
post_data = {"ukey": ukey, "ab": "0"}
+ res = json_loads(self.load(json_url, post=post_data))
+
+ self.logDebug(res)
- json_response = json_loads(self.load(json_url, post=post_data))
- self.logDebug(json_response)
- if json_response['status'] == 3:
+ if res['status'] == 3:
self.offline()
- if json_response['captcha']:
- captcha_key = re.search(self.RECAPTCHA_KEY_PATTERN, self.html).group(1)
+ if res['captcha']:
+ captcha_key = re.search(self.RECAPTCHA_PATTERN, self.html).group(1)
+
recaptcha = ReCaptcha(self)
post_data['ctype'] = "recaptcha"
- for _ in xrange(5):
- post_data['recaptcha_challenge'], post_data['recaptcha_response'] = recaptcha.challenge(captcha_key)
- json_response = json_loads(self.load(json_url, post=post_data))
- self.logDebug(json_response)
+ for _i in xrange(5):
+ challenge, response = recaptcha.challenge(captcha_key)
+ post_data.update({'recaptcha_challenge': challenge,
+ 'recaptcha_response' : response})
+ res = json_loads(self.load(json_url, post=post_data))
+ self.logDebug(res)
- if json_response['retry']:
+ if res['retry']:
self.invalidCaptcha()
else:
self.correctCaptcha()
break
else:
- self.fail("Incorrect captcha")
+ self.fail(_("Incorrect captcha"))
- if not "ticket_url" in json_response:
- self.parseError("Download URL")
+ if not "ticket_url" in res:
+ self.error(_("No download URL"))
- self.download(json_response['ticket_url'])
+ self.download(res['ticket_url'])
getInfo = create_getInfo(IfileIt)
diff --git a/module/plugins/hoster/IfolderRu.py b/module/plugins/hoster/IfolderRu.py
index 912dbd491..255f10f45 100644
--- a/module/plugins/hoster/IfolderRu.py
+++ b/module/plugins/hoster/IfolderRu.py
@@ -1,48 +1,39 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class IfolderRu(SimpleHoster):
- __name__ = "IfolderRu"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(?:ifolder\.ru|rusfolder\.(?:com|net|ru))/(?:files/)?(?P<ID>\d+).*'
+ __name__ = "IfolderRu"
+ __type__ = "hoster"
__version__ = "0.38"
+
+ __pattern__ = r'http://(?:www\.)?(?:ifolder\.ru|rusfolder\.(?:com|net|ru))/(?:files/)?(?P<ID>\d+)'
+
__description__ = """Ifolder.ru hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_SIZE_REPLACEMENTS = [(u'Кб', 'KB'), (u'Мб', 'MB'), (u'Гб', 'GB')]
- FILE_NAME_PATTERN = ur'(?:<div><span>)?НазваМОе:(?:</span>)? <b>(?P<N>[^<]+)</b><(?:/div|br)>'
- FILE_SIZE_PATTERN = ur'(?:<div><span>)?РазЌер:(?:</span>)? <b>(?P<S>[^<]+)</b><(?:/div|br)>'
+ 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'"
+ 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_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 = True if self.account else False
self.chunkLimit = 1
+
def process(self, pyfile):
file_id = re.match(self.__pattern__, pyfile.url).group('ID')
self.html = self.load("http://rusfolder.com/%s" % file_id, cookies=True, decode=True)
@@ -60,7 +51,7 @@ class IfolderRu(SimpleHoster):
self.wait(31, False)
captcha_url = "http://ints.rusfolder.com/random/images/?session=%s" % session_id
- for _ in xrange(5):
+ 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)
@@ -75,11 +66,10 @@ class IfolderRu(SimpleHoster):
else:
break
else:
- self.fail("Invalid captcha")
+ self.fail(_("Invalid captcha"))
download_url = re.search(self.LINK_PATTERN, self.html).group(1)
self.correctCaptcha()
- self.logDebug("Download URL: %s" % download_url)
self.download(download_url)
diff --git a/module/plugins/hoster/JumbofilesCom.py b/module/plugins/hoster/JumbofilesCom.py
index ad648dacf..cabc0f098 100644
--- a/module/plugins/hoster/JumbofilesCom.py
+++ b/module/plugins/hoster/JumbofilesCom.py
@@ -1,31 +1,37 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class JumbofilesCom(SimpleHoster):
- __name__ = "JumbofilesCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?jumbofiles.com/(\w{12}).*'
+ __name__ = "JumbofilesCom"
+ __type__ = "hoster"
__version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?jumbofiles\.com/(\w{12})'
+
__description__ = """JumboFiles.com hoster plugin"""
- __author_name__ = "godofdream"
- __author_mail__ = "soilfiction@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("godofdream", "soilfiction@gmail.com")]
- FILE_INFO_PATTERN = r'<TR><TD>(?P<N>[^<]+?)\s*<small>\((?P<S>[\d.]+)\s*(?P<U>[KMG][bB])\)</small></TD></TR>'
+
+ 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_PATTERN = r'<meta http-equiv="refresh" content="10;url=(.+)">'
+
def setup(self):
- self.resumeDownload = self.multiDL = True
+ self.resumeDownload = True
+ self.multiDL = True
+
def handleFree(self):
ukey = re.match(self.__pattern__, self.pyfile.url).group(1)
post_data = {"id": ukey, "op": "download3", "rand": ""}
html = self.load(self.pyfile.url, post=post_data, decode=True)
url = re.search(self.LINK_PATTERN, html).group(1)
- self.logDebug("Download " + url)
self.download(url)
diff --git a/module/plugins/hoster/JunocloudMe.py b/module/plugins/hoster/JunocloudMe.py
new file mode 100644
index 000000000..56d6588fa
--- /dev/null
+++ b/module/plugins/hoster/JunocloudMe.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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")]
+
+
+ HOSTER_DOMAIN = "junocloud.me"
+
+ 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 12df08743..000000000
--- a/module/plugins/hoster/Keep2shareCC.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-# Test links (random.bin):
-# http://k2s.cc/file/55fb73e1c00c5/random.bin
-
-import re
-from urlparse import urlparse, urljoin
-
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-from module.plugins.internal.CaptchaService import ReCaptcha
-
-
-class Keep2shareCC(SimpleHoster):
- __name__ = "Keep2shareCC"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?(keep2share|k2s|keep2s)\.cc/file/(?P<ID>\w+)'
- __version__ = "0.10"
- __description__ = """Keep2share.cc hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- FILE_NAME_PATTERN = r'File: <span>(?P<N>.+)</span>'
- FILE_SIZE_PATTERN = r'Size: (?P<S>[^<]+)</div>'
- OFFLINE_PATTERN = r'File not found or deleted|Sorry, this file is blocked or deleted|Error 404'
-
- LINK_PATTERN = r'To download this file with slow speed, use <a href="([^"]+)">this link</a>'
- WAIT_PATTERN = r'Please wait ([\d:]+) to download this file'
- ALREADY_DOWNLOADING_PATTERN = r'Free account does not allow to download more than one file at the same time'
-
- RECAPTCHA_KEY = "6LcYcN0SAAAAABtMlxKj7X0hRxOY8_2U86kI1vbb"
-
-
- def handleFree(self):
- self.sanitize_url()
- self.html = self.load(self.pyfile.url)
-
- self.fid = re.search(r'<input type="hidden" name="slow_id" value="([^"]+)">', self.html).group(1)
- self.html = self.load(self.pyfile.url, post={'yt0': '', 'slow_id': self.fid})
-
- m = re.search(r"function download\(\){.*window\.location\.href = '([^']+)';", self.html, re.DOTALL)
- if m: # Direct mode
- self.startDownload(m.group(1))
- else:
- self.handleCaptcha()
-
- self.wait(30)
-
- self.html = self.load(self.pyfile.url, post={'uniqueId': self.fid, 'free': 1})
-
- 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.wait(wait_time, reconnect=True)
- self.retry()
-
- m = re.search(self.ALREADY_DOWNLOADING_PATTERN, self.html)
- if m:
- # if someone is already downloading on our line, wait 30min and retry
- self.logDebug('Already downloading, waiting for 30 minutes')
- self.wait(30 * 60, reconnect=True)
- self.retry()
-
- m = re.search(self.LINK_PATTERN, self.html)
- if m is None:
- self.parseError("Unable to detect direct link")
- self.startDownload(m.group(1))
-
- def handleCaptcha(self):
- recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
- post_data = {'recaptcha_challenge_field': challenge,
- 'recaptcha_response_field': response,
- 'CaptchaForm%5Bcode%5D': '',
- 'free': 1,
- 'freeDownloadRequest': 1,
- 'uniqueId': self.fid,
- 'yt0': ''}
-
- self.html = self.load(self.pyfile.url, post=post_data)
-
- if 'recaptcha' not in self.html:
- self.correctCaptcha()
- break
- else:
- self.logInfo('Wrong captcha')
- self.invalidCaptcha()
- else:
- self.fail("All captcha attempts failed")
-
- def startDownload(self, url):
- d = urljoin(self.base_url, url)
- self.logDebug('Direct Link: ' + d)
- self.download(d, disposition=True)
-
- def sanitize_url(self):
- header = self.load(self.pyfile.url, just_header=True)
- if 'location' in header:
- self.pyfile.url = header['location']
- p = urlparse(self.pyfile.url)
- self.base_url = "%s://%s" % (p.scheme, p.hostname)
-
-
-getInfo = create_getInfo(Keep2shareCC)
diff --git a/module/plugins/hoster/Keep2shareCc.py b/module/plugins/hoster/Keep2shareCc.py
new file mode 100644
index 000000000..86c28e93b
--- /dev/null
+++ b/module/plugins/hoster/Keep2shareCc.py
@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from urlparse import urljoin, urlparse
+
+from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import _isDirectLink, SimpleHoster, create_getInfo
+
+
+class Keep2shareCc(SimpleHoster):
+ __name__ = "Keep2shareCc"
+ __type__ = "hoster"
+ __version__ = "0.18"
+
+ __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 = LINK_PREMIUM_PATTERN = r'"([^"]+url.html?file=.+?)"|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):
+ self.fid = re.search(r'<input type="hidden" name="slow_id" value="([^"]+)">', self.html).group(1)
+ self.html = self.load(self.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(self.pyfile.url, post={'uniqueId': self.fid, 'free': 1})
+
+ self.checkErrors()
+
+ 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)
+
+
+ def handleCaptcha(self):
+ recaptcha = ReCaptcha(self)
+
+ for _i in xrange(5):
+ 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:
+ challenge, response = recaptcha.challenge()
+ post_data.update({'recaptcha_challenge_field': challenge,
+ 'recaptcha_response_field' : response})
+
+ self.html = self.load(self.pyfile.url, post=post_data)
+
+ if 'recaptcha' not in self.html:
+ self.correctCaptcha()
+ break
+ else:
+ self.invalidCaptcha()
+ else:
+ self.fail(_("All captcha attempts failed"))
+
+
+ def downloadLink(self, link):
+ if not link or not isinstance(link, basestring):
+ return
+
+ link = _isDirectLink(self, link, self.premium)
+
+ if link:
+ self.download(urljoin("http://k2s.cc/", link), disposition=True)
+
+
+getInfo = create_getInfo(Keep2shareCc)
diff --git a/module/plugins/hoster/KickloadCom.py b/module/plugins/hoster/KickloadCom.py
new file mode 100644
index 000000000..1c39db46c
--- /dev/null
+++ b/module/plugins/hoster/KickloadCom.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
new file mode 100644
index 000000000..13cbf4781
--- /dev/null
+++ b/module/plugins/hoster/KingfilesNet.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.internal.CaptchaService import SolveMedia
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class KingfilesNet(SimpleHoster):
+ __name__ = "KingfilesNet"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __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_PATTERN = r'var download_url = \'(.+)\';'
+
+
+ def setup(self):
+ self.resumeDownload = True
+ self.multiDL = True
+
+
+ def handleFree(self):
+ # Click the free user button
+ post_data = {'op' : "download1",
+ 'usr_login' : "",
+ 'id' : self.info['pattern']['ID'],
+ 'fname' : self.pyfile.name,
+ 'referer' : "",
+ 'method_free': "+"}
+
+ self.html = self.load(self.pyfile.url, post=post_data, cookies=True, decode=True)
+
+ solvemedia = SolveMedia(self)
+ challenge, response = 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' : self.pyfile.url,
+ 'method_free' : "+",
+ 'method_premium' : "",
+ 'adcopy_response' : response,
+ 'adcopy_challenge': challenge,
+ 'down_direct' : "1"}
+
+ self.html = self.load(self.pyfile.url, post=post_data, cookies=True, decode=True)
+
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ self.error(_("Download url not found"))
+
+ self.download(m.group(1), cookies=True, disposition=True)
+
+ check = self.checkDownload({'html': re.compile("<html>")})
+ if check == "html":
+ self.error(_("Downloaded file is an html page"))
+
+
+getInfo = create_getInfo(KingfilesNet)
diff --git a/module/plugins/hoster/LemUploadsCom.py b/module/plugins/hoster/LemUploadsCom.py
index 0d4facea2..22fbd60dd 100644
--- a/module/plugins/hoster/LemUploadsCom.py
+++ b/module/plugins/hoster/LemUploadsCom.py
@@ -1,24 +1,18 @@
# -*- coding: utf-8 -*-
-# Test links:
-# BigBuckBunny_320x180.mp4 - 61.7 Mb - http://lemuploads.com/uwol0aly9dld
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+class LemUploadsCom(DeadHoster):
+ __name__ = "LemUploadsCom"
+ __type__ = "hoster"
+ __version__ = "0.02"
-class LemUploadsCom(XFileSharingPro):
- __name__ = "LemUploadsCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?lemuploads.com/\w{12}'
- __version__ = "0.01"
- __description__ = """LemUploads.com hoster plugin"""
- __author_name__ = "t4skforce"
- __author_mail__ = "t4skforce1337[AT]gmail[DOT]com"
-
- HOSTER_NAME = "lemuploads.com"
+ __pattern__ = r'https?://(?:www\.)?lemuploads\.com/\w{12}'
- OFFLINE_PATTERN = r'<b>File Not Found</b><br><br>'
- FILE_NAME_PATTERN = r'<b>Password:</b></div>\s*<h2>(?P<N>[^<]+)</h2>'
+ __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
index 1a5928f17..a7b11047f 100644
--- a/module/plugins/hoster/LetitbitNet.py
+++ b/module/plugins/hoster/LetitbitNet.py
@@ -1,39 +1,25 @@
# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
+#
# API Documentation:
# http://api.letitbit.net/reg/static/api.pdf
-# Test links (random.bin):
+#
+# Test links:
# http://letitbit.net/download/07874.0b5709a7d3beee2408bb1f2eefce/random.bin.html
import re
-import urllib
-from module.common.json_layer import json_loads, json_dumps
+from urllib import urlencode, urlopen
+from urlparse import urljoin
-from module.plugins.hoster.UnrestrictLi import secondsToMidnight
+from module.common.json_layer import json_loads, json_dumps
from module.plugins.internal.CaptchaService import ReCaptcha
-from module.plugins.internal.SimpleHoster import SimpleHoster
+from module.plugins.internal.SimpleHoster import SimpleHoster, secondsToMidnight
def api_download_info(url):
json_data = ["yw7XQy2v9", ["download/info", {"link": url}]]
- post_data = urllib.urlencode({'r': json_dumps(json_data)})
- api_rep = urllib.urlopen("http://api.letitbit.net/json", data=post_data).read()
+ post_data = urlencode({'r': json_dumps(json_data)})
+ api_rep = urlopen("http://api.letitbit.net/json", data=post_data).read()
return json_loads(api_rep)
@@ -48,26 +34,27 @@ def getInfo(urls):
class LetitbitNet(SimpleHoster):
- __name__ = "LetitbitNet"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(letitbit|shareflare).net/download/.*'
- __version__ = "0.24"
+ __name__ = "LetitbitNet"
+ __type__ = "hoster"
+ __version__ = "0.27"
+
+ __pattern__ = r'https?://(?:www\.)?(letitbit|shareflare)\.net/download/.+'
+
__description__ = """Letitbit.net hoster plugin"""
- __author_name__ = ("zoidberg", "z00nx")
- __author_mail__ = ("zoidberg@mujmail.cz", "z00nx0@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("z00nx", "z00nx0@gmail.com")]
- FILE_URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "letitbit.net")]
- HOSTER_NAME = "letitbit.net"
+ URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "letitbit.net")]
SECONDS_PATTERN = r'seconds\s*=\s*(\d+);'
- CAPTCHA_CONTROL_FIELD = r"recaptcha_control_field\s=\s'(?P<value>[^']+)'"
- RECAPTCHA_KEY = "6Lc9zdMSAAAAAF-7s2wuQ-036pLRbM0p8dDaQdAM"
+ CAPTCHA_CONTROL_FIELD = r'recaptcha_control_field\s=\s\'(.+?)\''
def setup(self):
self.resumeDownload = True
- #TODO confirm that resume works
+
def getFileInfo(self):
api_rep = api_download_info(self.pyfile.url)
@@ -78,33 +65,17 @@ class LetitbitNet(SimpleHoster):
else:
self.offline()
+
def handleFree(self):
action, inputs = self.parseHtmlForm('id="ifree_form"')
if not action:
- self.parseError("page 1 / ifree_form")
+ self.error(_("ifree_form"))
- domain = "http://www." + self.HOSTER_NAME
self.pyfile.size = float(inputs['sssize'])
self.logDebug(action, inputs)
inputs['desc'] = ""
- self.html = self.load(domain + action, post=inputs, cookies=True)
-
- # action, inputs = self.parseHtmlForm('id="d3_form"')
- # if not action:
- # self.parseError("page 2 / d3_form")
- # self.logDebug(action, inputs)
- #
- # self.html = self.load(action, post = inputs, cookies = True)
- #
- # try:
- # ajax_check_url, captcha_url = re.search(self.CHECK_URL_PATTERN, self.html).groups()
- # m = re.search(self.SECONDS_PATTERN, self.html)
- # seconds = int(m.group(1)) if m else 60
- # self.wait(seconds+1)
- # except Exception, e:
- # self.logError(e)
- # self.parseError("page 3 / js")
+ 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
@@ -112,47 +83,48 @@ class LetitbitNet(SimpleHoster):
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 + 1)
+ self.wait(seconds)
- response = self.load("%s/ajax/download3.php" % domain, post=" ", cookies=True)
- if response != '1':
- self.parseError('Unknown response - ajax_check_url')
- self.logDebug(response)
+ 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)
- challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
- post_data = {"recaptcha_challenge_field": challenge, "recaptcha_response_field": response,
+ challenge, response = 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)
- response = self.load('%s/ajax/check_recaptcha.php' % domain, post=post_data, cookies=True)
- self.logDebug(response)
- if not response:
+ res = self.load("http://letitbit.net/ajax/check_recaptcha.php", post=post_data, cookies=True)
+ self.logDebug(res)
+ if not res:
self.invalidCaptcha()
- if response == "error_free_download_blocked":
- self.logWarning("Daily limit reached")
+ if res == "error_free_download_blocked":
+ self.logWarning(_("Daily limit reached"))
self.wait(secondsToMidnight(gmt=2), True)
- if response == "error_wrong_captcha":
- self.logError("Wrong Captcha")
+ if res == "error_wrong_captcha":
self.invalidCaptcha()
self.retry()
- elif response.startswith('['):
- urls = json_loads(response)
- elif response.startswith('http://'):
- urls = [response]
+ elif res.startswith('['):
+ urls = json_loads(res)
+ elif res.startswith('http://'):
+ urls = [res]
else:
- self.parseError("Unknown response - captcha check")
+ self.error(_("Unknown response - captcha check"))
self.correctCaptcha()
for download_url in urls:
try:
- self.logDebug("Download URL", download_url)
self.download(download_url)
break
except Exception, e:
self.logError(e)
else:
- self.fail("Download did not finish correctly")
+ self.fail(_("Download did not finish correctly"))
+
def handlePremium(self):
api_key = self.user
@@ -160,13 +132,10 @@ class LetitbitNet(SimpleHoster):
json_data = [api_key, ["download/direct_links", {"pass": premium_key, "link": self.pyfile.url}]]
api_rep = self.load('http://api.letitbit.net/json', post={'r': json_dumps(json_data)})
- self.logDebug('API Data: ' + api_rep)
+ self.logDebug("API Data: " + api_rep)
api_rep = json_loads(api_rep)
if api_rep['status'] == 'FAIL':
self.fail(api_rep['data'])
- direct_link = api_rep['data'][0][0]
- self.logDebug('Direct Link: ' + direct_link)
-
- self.download(direct_link, disposition=True)
+ self.download(api_rep['data'][0][0], disposition=True)
diff --git a/module/plugins/hoster/LinestorageCom.py b/module/plugins/hoster/LinestorageCom.py
new file mode 100644
index 000000000..a3caacc0c
--- /dev/null
+++ b/module/plugins/hoster/LinestorageCom.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+
+class LinestorageCom(XFSHoster):
+ __name__ = "LinestorageCom"
+ __type__ = "hoster"
+ __version__ = "0.01"
+
+ __pattern__ = r'http://(?:www\.)?linestorage\.com/\w{12}'
+
+ __description__ = """Linestorage.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = "linestorage.com"
+
+
+getInfo = create_getInfo(LinestorageCom)
diff --git a/module/plugins/hoster/LinksnappyCom.py b/module/plugins/hoster/LinksnappyCom.py
index 3de19945b..90a47d1ac 100644
--- a/module/plugins/hoster/LinksnappyCom.py
+++ b/module/plugins/hoster/LinksnappyCom.py
@@ -1,68 +1,75 @@
# -*- coding: utf-8 -*-
import re
+
from urlparse import urlsplit
-from module.plugins.Hoster import Hoster
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.06"
-class LinksnappyCom(Hoster):
- __name__ = "LinksnappyCom"
- __version__ = "0.02"
- __type__ = "hoster"
__pattern__ = r'https?://(?:[^/]*\.)?linksnappy\.com'
+
__description__ = """Linksnappy.com hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
SINGLE_CHUNK_HOSTERS = ('easybytez.com')
+
def setup(self):
- self.chunkLimit = -1
+ self.chunkLimit = -1
self.resumeDownload = True
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "Linksnappy.com")
- self.fail("No Linksnappy.com account provided")
- else:
- self.logDebug("Old URL: %s" % pyfile.url)
- 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]
+ def handlePremium(self):
+ host = self._get_host(self.pyfile.url)
+ json_params = json_dumps({'link': self.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)
- if j['error']:
- self.logError('Error converting the link: %s' % j['error'])
- self.fail('Error converting the link')
+ j = json_loads(r)['links'][0]
- pyfile.name = j['filename']
- new_url = j['generated']
+ if j['error']:
+ msg = _("Error converting the link")
+ self.logError(msg, j['error'])
+ self.fail(msg)
- if host in self.SINGLE_CHUNK_HOSTERS:
- self.chunkLimit = 1
- else:
- self.setup()
+ self.pyfile.name = j['filename']
+ self.link = j['generated']
- if new_url != pyfile.url:
- self.logDebug("New URL: " + new_url)
+ if host in self.SINGLE_CHUNK_HOSTERS:
+ self.chunkLimit = 1
+ else:
+ self.setup()
- self.download(new_url, disposition=True)
+ if self.link != self.pyfile.url:
+ self.logDebug("New URL: " + self.link)
+
+
+ def checkFile(self):
+ super(LinksnappyCom, self).checkFile()
check = self.checkDownload({"html302": "<title>302 Found</title>"})
+
if check == "html302":
- self.retry(wait_time=5, reason="Linksnappy returns only HTML data.")
+ self.retry(wait_time=5, reason=_("Linksnappy returns only HTML data"))
+
@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
index af86cd026..0a5b26410 100644
--- a/module/plugins/hoster/LoadTo.py
+++ b/module/plugins/hoster/LoadTo.py
@@ -1,20 +1,6 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-# Test links (random.bin):
+#
+# Test links:
# http://www.load.to/JWydcofUY6/random.bin
# http://www.load.to/oeSmrfkXE/random100.bin
@@ -25,56 +11,65 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class LoadTo(SimpleHoster):
- __name__ = "LoadTo"
- __version__ = "0.15"
- __type__ = "hoster"
+ __name__ = "LoadTo"
+ __type__ = "hoster"
+ __version__ = "0.18"
__pattern__ = r'http://(?:www\.)?load\.to/\w+'
- __description__ = """Load.to hoster plugin"""
- __author_name__ = ("halfman", "stickell")
- __author_mail__ = ("Pulpan3@gmail.com", "l.stickell@yahoo.it")
+ __description__ = """ Load.to hoster plugin """
+ __license__ = "GPLv3"
+ __authors__ = [("halfman", "Pulpan3@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
- FILE_NAME_PATTERN = r'<head><title>(?P<N>.+) \/\/ Load.to</title>'
- FILE_SIZE_PATTERN = r'<a [^>]+>(?P<Z>.+)</a></h3>\s*Size: (?P<S>.*) (?P<U>[kKmMgG]?i?[bB])'
- OFFLINE_PATTERN = r'Can\'t find file\. Please check URL'
+
+ 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_PATTERN = r'<form method="post" action="(.+?)"'
WAIT_PATTERN = r'type="submit" value="Download \((\d+)\)"'
- SOLVEMEDIA_PATTERN = r'http://api\.solvemedia\.com/papi/challenge\.noscript\?k=([^"]+)'
+
+ URL_REPLACEMENTS = [(r'(\w)$', r'\1/')]
def setup(self):
self.multiDL = True
self.chunkLimit = 1
+
def handleFree(self):
# Search for Download URL
m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.parseError("Unable to detect download URL")
+ self.error(_("LINK_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))
+ self.wait(int(m.group(1)))
# Load.to is using solvemedia captchas since ~july 2014:
- m = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if m is None:
+ solvemedia = SolveMedia(self)
+ captcha_key = solvemedia.detect_key()
+
+ if captcha_key is None:
self.download(download_url)
else:
- captcha_key = m.group(1)
- solvemedia = SolveMedia(self)
- captcha_challenge, captcha_response = solvemedia.challenge(captcha_key)
- self.download(download_url, post={"adcopy_challenge": captcha_challenge, "adcopy_response": captcha_response})
- check = self.checkDownload({"404": re.compile("\A<h1>404 Not Found</h1>")})
+ challenge, response = solvemedia.challenge(captcha_key)
+
+ self.download(download_url, post={"adcopy_challenge": challenge, "adcopy_response": response})
+
+ check = self.checkDownload({'404': re.compile("\A<h1>404 Not Found</h1>"), 'html': re.compile("html")})
+
if check == "404":
- self.logWarning("The captcha you entered was incorrect. Please try again.")
self.invalidCaptcha()
self.retry()
+ elif check == "html":
+ self.logWarning(_("Downloaded file is an html page, will retry"))
+ self.retry()
getInfo = create_getInfo(LoadTo)
diff --git a/module/plugins/hoster/LomafileCom.py b/module/plugins/hoster/LomafileCom.py
index 9f05d952e..475cdacaa 100644
--- a/module/plugins/hoster/LomafileCom.py
+++ b/module/plugins/hoster/LomafileCom.py
@@ -1,55 +1,19 @@
-import re
+# -*- coding: utf-8 -*-
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-class LomafileCom(SimpleHoster):
- __name__ = "LomafileCom"
- __type__ = "hoster"
- __pattern__ = r'https?://lomafile\.com/.+/[\w\.]+'
- __version__ = "0.1"
- __description__ = """Lomafile.com hoster plugin"""
- __author_name__ = "nath_schwarz"
- __author_mail__ = "nathan.notwhite@gmail.com"
-
- FILE_NAME_PATTERN = r'Filename:[^>]*>(?P<N>[\w\.]+)'
- FILE_SIZE_PATTERN = r'\((?P<S>\d+)\s(?P<U>\w+)\)'
- FILE_OFFLINE_PATTERN = r'Software error'
-
- def handleFree(self):
- for _ in range(3):
- captcha_id = re.search(r'src="http://lomafile\.com/captchas/(?P<id>\w+)\.jpg"', self.html)
- if not captcha_id:
- self.parseError("Unable to parse captcha id.")
- else:
- captcha_id = captcha_id.group("id")
+class LomafileCom(DeadHoster):
+ __name__ = "LomafileCom"
+ __type__ = "hoster"
+ __version__ = "0.52"
- form_id = re.search(r'name="id" value="(?P<id>\w+)"', self.html)
- if not form_id:
- self.parseError("Unable to parse form id")
- else:
- form_id = form_id.group("id")
+ __pattern__ = r'http://lomafile\.com/\w{12}'
- captcha = self.decryptCaptcha("http://lomafile.com/captchas/" + captcha_id + ".jpg")
-
- self.wait(60)
-
- self.html = self.load(self.pyfile.url, post={
- "op": "download2",
- "id": form_id,
- "rand": captcha_id,
- "code": captcha,
- "down_direct": "1"})
+ __description__ = """Lomafile.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com"),
+ ("guidobelix", "guidobelix@hotmail.it")]
- download_url = re.search(r'http://[\d\.]+:\d+/d/\w+/[\w\.]+', self.html)
- if download_url is None:
- self.invalidCaptcha()
- self.logDebug("Invalid captcha.")
- else:
- download_url = download_url.group(0)
- self.logDebug("Download URL: %s" % download_url)
- self.download(download_url)
- else:
- self.fail("Invalid captcha-code entered.")
getInfo = create_getInfo(LomafileCom)
diff --git a/module/plugins/hoster/LuckyShareNet.py b/module/plugins/hoster/LuckyShareNet.py
index 9479f583e..2c33b57e7 100644
--- a/module/plugins/hoster/LuckyShareNet.py
+++ b/module/plugins/hoster/LuckyShareNet.py
@@ -1,24 +1,27 @@
# -*- coding: utf-8 -*-
import re
-from module.lib.bottle import json_loads
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+from bottle import json_loads
+
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class LuckyShareNet(SimpleHoster):
- __name__ = "LuckyShareNet"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?luckyshare.net/(?P<ID>\d{10,})'
- __version__ = "0.02"
+ __name__ = "LuckyShareNet"
+ __type__ = "hoster"
+ __version__ = "0.04"
+
+ __pattern__ = r'https?://(?:www\.)?luckyshare\.net/(?P<ID>\d{10,})'
+
__description__ = """LuckyShare.net hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
- FILE_INFO_PATTERN = r"<h1 class='file_name'>(?P<N>\S+)</h1>\s*<span class='file_size'>Filesize: (?P<S>[\d.]+)(?P<U>\w+)</span>"
+ 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'
- RECAPTCHA_KEY = "6LdivsgSAAAAANWh-d7rPE1mus4yVWuSQIJKIYNw"
def parseJson(self, rep):
@@ -26,46 +29,44 @@ class LuckyShareNet(SimpleHoster):
html = self.load(self.pyfile.url, decode=True)
m = re.search(r"waitingtime = (\d+);", html)
if m:
- waittime = int(m.group(1))
- self.logDebug('You have to wait %d seconds between free downloads' % waittime)
- self.retry(wait_time=waittime)
+ seconds = int(m.group(1))
+ self.logDebug("You have to wait %d seconds between free downloads" % seconds)
+ self.retry(wait_time=seconds)
else:
- self.parseError('Unable to detect wait time between free downloads')
+ self.error(_("Unable to detect wait time between free downloads"))
elif 'Hash expired' in rep:
- self.retry(reason="Hash expired")
+ 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):
- file_id = re.match(self.__pattern__, self.pyfile.url).group('ID')
- self.logDebug('File ID: ' + file_id)
- rep = self.load(r"http://luckyshare.net/download/request/type/time/file/" + file_id, decode=True)
- self.logDebug('JSON: ' + rep)
+ 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(int(json['time']))
recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
+
+ for _i in xrange(5):
+ challenge, response = 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)
+ self.logDebug("JSON: " + rep)
if 'link' in rep:
json.update(self.parseJson(rep))
self.correctCaptcha()
break
elif 'Verification failed' in rep:
- self.logInfo('Wrong captcha')
self.invalidCaptcha()
else:
- self.parseError('Unable to get downlaod link')
+ self.error(_("Unable to get downlaod link"))
if not json['link']:
- self.fail("No Download url retrieved/all captcha attempts failed")
+ self.fail(_("No Download url retrieved/all captcha attempts failed"))
- self.logDebug('Direct URL: ' + json['link'])
self.download(json['link'])
diff --git a/module/plugins/hoster/MediafireCom.py b/module/plugins/hoster/MediafireCom.py
index 3281f66e6..782d78ce1 100644
--- a/module/plugins/hoster/MediafireCom.py
+++ b/module/plugins/hoster/MediafireCom.py
@@ -1,23 +1,9 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo
+
from module.plugins.internal.CaptchaService import SolveMedia
+from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo
from module.network.RequestFactory import getURL
@@ -27,68 +13,76 @@ def replace_eval(js_expr):
def checkHTMLHeader(url):
try:
- for _ in xrange(3):
+ for _i in xrange(3):
header = getURL(url, just_header=True)
+
for line in header.splitlines():
line = line.lower()
+
if 'location' in line:
url = line.split(':', 1)[1].strip()
if 'error.php?errno=320' in url:
return url, 1
+
if not url.startswith('http://'):
url = 'http://www.mediafire.com' + url
+
break
+
elif 'content-disposition' in line:
return url, 2
else:
break
except:
return url, 3
-
- return url, 0
+ else:
+ return url, 0
def getInfo(urls):
for url in urls:
location, status = checkHTMLHeader(url)
+
if status:
file_info = (url, 0, status, url)
else:
file_info = parseFileInfo(MediafireCom, url, getURL(url, decode=True))
+
yield file_info
class MediafireCom(SimpleHoster):
- __name__ = "MediafireCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?mediafire\.com/(file/|(view/?|download.php)?\?)(\w{11}|\w{15})($|/)'
- __version__ = "0.79"
+ __name__ = "MediafireCom"
+ __type__ = "hoster"
+ __version__ = "0.82"
+
+ __pattern__ = r'http://(?:www\.)?mediafire\.com/(file/|(view/?|download\.php)?\?)(\w{11}|\w{15})($|/)'
+
__description__ = """Mediafire.com hoster plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
-
- LINK_PATTERN = r'<div class="download_link"[^>]*(?:z-index:(?P<zindex>\d+))?[^>]*>\s*<a href="(?P<href>http://[^"]+)"'
- JS_KEY_PATTERN = r"DoShow\('mfpromo1'\);[^{]*{((\w+)='';.*?)eval\(\2\);"
- JS_ZMODULO_PATTERN = r"\('z-index'\)\) \% (\d+)\)\);"
- SOLVEMEDIA_PATTERN = r'http://api\.solvemedia\.com/papi/challenge\.noscript\?k=([^"]+)'
- PAGE1_ACTION_PATTERN = r'<link rel="canonical" href="([^"]+)"/>'
- PASSWORD_PATTERN = r'<form name="form_password"'
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
- FILE_NAME_PATTERN = r'<META NAME="description" CONTENT="(?P<N>[^"]+)"/>'
- FILE_INFO_PATTERN = r"oFileSharePopup\.ald\('(?P<ID>[^']*)','(?P<N>[^']*)','(?P<S>[^']*)','','(?P<sha256>[^']*)'\)"
+ NAME_PATTERN = r'<META NAME="description" CONTENT="(?P<N>[^"]+)"/>'
+ INFO_PATTERN = r'oFileSharePopup\.ald\(\'(?P<ID>[^\']*)\',\'(?P<N>[^\']*)\',\'(?P<S>[^\']*)\',\'\',\'(?P<H>[^\']*)\'\)'
OFFLINE_PATTERN = r'class="error_msg_title"> Invalid or Deleted File. </div>'
+ PASSWORD_PATTERN = r'<form name="form_password"'
+
+
def setup(self):
self.multiDL = False
+
def process(self, pyfile):
pyfile.url = re.sub(r'/view/?\?', '/?', pyfile.url)
- self.url, result = checkHTMLHeader(pyfile.url)
- self.logDebug('Location (%d): %s' % (result, self.url))
+ self.link, result = checkHTMLHeader(pyfile.url)
+ self.logDebug("Location (%d): %s" % (result, self.link))
if result == 0:
- self.html = self.load(self.url, decode=True)
+ self.html = self.load(self.link, decode=True)
self.checkCaptcha()
self.multiDL = True
self.check_data = self.getFileInfo()
@@ -101,36 +95,34 @@ class MediafireCom(SimpleHoster):
self.offline()
else:
self.multiDL = True
- self.download(self.url, disposition=True)
+ self.download(self.link, disposition=True)
+
def handleFree(self):
- passwords = self.getPassword().splitlines()
- while self.PASSWORD_PATTERN in self.html:
- if len(passwords):
- password = passwords.pop(0)
- self.logInfo("Password protected link, trying " + password)
- self.html = self.load(self.url, post={"downloadp": password})
+ if self.PASSWORD_PATTERN in self.html:
+ password = self.getPassword()
+
+ if password:
+ self.logInfo(_("Password protected link, trying ") + password)
+ self.html = self.load(self.link, post={"downloadp": password})
+
+ if self.PASSWORD_PATTERN in self.html:
+ self.fail(_("Incorrect password"))
else:
- self.fail("No or incorrect password")
+ self.fail(_("No password found"))
m = re.search(r'kNO = r"(http://.*?)";', self.html)
if m is None:
- self.parseError("Download URL")
- download_url = m.group(1)
- self.logDebug("DOWNLOAD LINK:", download_url)
+ self.error(_("No download URL"))
+ download_url = m.group(1)
self.download(download_url)
+
def checkCaptcha(self):
- for _ in xrange(5):
- m = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if m:
- captcha_key = m.group(1)
- solvemedia = SolveMedia(self)
- captcha_challenge, captcha_response = solvemedia.challenge(captcha_key)
- self.html = self.load(self.url, post={"adcopy_challenge": captcha_challenge,
- "adcopy_response": captcha_response}, decode=True)
- else:
- break
- else:
- self.fail("No valid recaptcha solution received")
+ solvemedia = SolveMedia(self)
+ challenge, response = solvemedia.challenge()
+ self.html = self.load(self.link,
+ post={'adcopy_challenge': challenge,
+ 'adcopy_response' : response},
+ decode=True)
diff --git a/module/plugins/hoster/MegaNz.py b/module/plugins/hoster/MegaCoNz.py
index cf35f2d2d..fc6724dc7 100644
--- a/module/plugins/hoster/MegaNz.py
+++ b/module/plugins/hoster/MegaCoNz.py
@@ -1,54 +1,86 @@
# -*- coding: utf-8 -*-
-import re
import random
+import re
+
from array import array
-from os import remove
from base64 import standard_b64decode
+from os import remove
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
-#def getInfo(urls):
-# pass
-
+############################ 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.17"
+
+ __pattern__ = r'https?://(?:www\.)?mega\.co\.nz/#!(?P<ID>[\w!-]+)'
-class MegaNz(Hoster):
- __name__ = "MegaNz"
- __type__ = "hoster"
- __pattern__ = r'https?://([a-z0-9]+\.)?mega\.co\.nz/#!([a-zA-Z0-9!_\-]+)'
- __version__ = "0.14"
__description__ = """Mega.co.nz hoster plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "ranan@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "ranan@pyload.org")]
- API_URL = "https://g.api.mega.co.nz/cs?id=%d"
+ API_URL = "https://g.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", key)
key_array = array("I", [a[0] ^ a[4], a[1] ^ a[5], a[2] ^ a[6], a[3] ^ a[7]])
return key_array
+
def callApi(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)
- resp = self.load(self.API_URL % uid, post=json_dumps([kwargs]))
- self.logDebug("Api Response: " + resp)
- return json_loads(resp)
+ 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):
+ def decryptAttr(self, data, key):
cbc = AES.new(self.getCipherKey(key), AES.MODE_CBC, "\0" * 16)
attr = cbc.decrypt(self.b64_decode(data))
self.logDebug("Decrypted Attr: " + attr)
@@ -56,7 +88,8 @@ class MegaNz(Hoster):
self.fail(_("Decryption failed"))
# Data is padded, 0-bytes must be stripped
- return json_loads(attr.replace("MEGA", "").rstrip("\0").strip())
+ return json_loads(re.search(r'{.+?}', attr).group(0))
+
def decryptFile(self, key):
""" Decrypts the file at lastDownload` """
@@ -72,8 +105,12 @@ class MegaNz(Hoster):
file_crypted = self.lastDownload
file_decrypted = file_crypted.rsplit(self.FILE_SUFFIX)[0]
- f = open(file_crypted, "rb")
- df = open(file_decrypted, "wb")
+
+ try:
+ f = open(file_crypted, "rb")
+ df = open(file_decrypted, "wb")
+ except IOError, e:
+ self.fail(str(e))
# TODO: calculate CBC-MAC for checksum
@@ -91,16 +128,16 @@ class MegaNz(Hoster):
self.lastDownload = file_decrypted
- def process(self, pyfile):
+ def process(self, pyfile):
key = None
# match is guaranteed because plugin was chosen to handle url
- node = re.match(self.__pattern__, pyfile.url).group(2)
+ node = re.match(self.__pattern__, pyfile.url).group('ID')
if "!" in node:
- node, key = node.split("!")
+ node, key = node.split("!", 1)
- self.logDebug("File id: %s | Key: %s" % (node, key))
+ self.logDebug("ID: %s | Key: %s" % (node, key))
if not key:
self.fail(_("No file key provided in the URL"))
@@ -125,6 +162,8 @@ class MegaNz(Hoster):
pyfile.name = attr['n'] + self.FILE_SUFFIX
+ self.req.http.c.setopt(SSL_CIPHER_LIST, "RC4-MD5:DEFAULT")
+
self.download(dl['g'])
self.decryptFile(key)
diff --git a/module/plugins/hoster/MegaDebridEu.py b/module/plugins/hoster/MegaDebridEu.py
index 1e68cec22..6b9f463d5 100644
--- a/module/plugins/hoster/MegaDebridEu.py
+++ b/module/plugins/hoster/MegaDebridEu.py
@@ -1,61 +1,46 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
+
from urllib import unquote_plus
-from module.plugins.Hoster import Hoster
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.44"
+ __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^_]+'
-class MegaDebridEu(Hoster):
- __name__ = "MegaDebridEu"
- __version__ = "0.4"
- __type__ = "hoster"
- __pattern__ = r'^https?://(?:w{3}\d+\.mega-debrid.eu|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/download/file/[^/]+/.+$'
__description__ = """mega-debrid.eu hoster plugin"""
- __author_name__ = "D.Ducatel"
- __author_mail__ = "dducatel@je-geek.fr"
+ __license__ = "GPLv3"
+ __authors__ = [("D.Ducatel", "dducatel@je-geek.fr")]
+
- # Define the base URL of MegaDebrid api
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 process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.exitOnFail(_("Please enter your %s account or deactivate this plugin") % "Mega-debrid.eu")
- else:
- if not self.connectToApi():
- self.exitOnFail(_("Unable to connect to %s") % "Mega-debrid.eu")
- self.logDebug("Old URL: %s" % pyfile.url)
- new_url = self.debridLink(pyfile.url)
- self.logDebug("New URL: " + new_url)
+ def handlePremium(self):
+ if not self.connectToApi():
+ self.exitOnFail("Unable to connect to Mega-debrid.eu")
- filename = self.getFilename(new_url)
+ self.link = self.debridLink(self.pyfile.url)
+ self.logDebug("New URL: " + self.link)
+
+ filename = self.getFilename(self.link)
if filename != "":
- pyfile.name = filename
- self.download(new_url, disposition=True)
+ self.pyfile.name = filename
+
def connectToApi(self):
"""
@@ -65,14 +50,15 @@ class MegaDebridEu(Hoster):
user, data = self.account.selectAccount()
jsonResponse = self.load(self.API_URL,
get={'action': 'connectUser', 'login': user, 'password': data['password']})
- response = json_loads(jsonResponse)
+ res = json_loads(jsonResponse)
- if response['response_code'] == "ok":
- self.token = response['token']
+ if res['response_code'] == "ok":
+ self.token = res['token']
return True
else:
return False
+
def debridLink(self, linkToDebrid):
"""
Debrid a link
@@ -80,21 +66,25 @@ class MegaDebridEu(Hoster):
"""
jsonResponse = self.load(self.API_URL, get={'action': 'getLink', 'token': self.token},
post={"link": linkToDebrid})
- response = json_loads(jsonResponse)
+ res = json_loads(jsonResponse)
- if response['response_code'] == "ok":
- debridedLink = response['debridLink'][1:-1]
+ 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.logError(_(msg))
self.resetAccount()
else:
- self.fail(msg)
+ self.fail(_(msg))
+
+
+getInfo = create_getInfo(MegaDebridEu)
diff --git a/module/plugins/hoster/MegaFilesSe.py b/module/plugins/hoster/MegaFilesSe.py
index e4895bc87..c3de57914 100644
--- a/module/plugins/hoster/MegaFilesSe.py
+++ b/module/plugins/hoster/MegaFilesSe.py
@@ -1,21 +1,18 @@
# -*- coding: utf-8 -*-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-class MegaFilesSe(XFileSharingPro):
- __name__ = "MegaFilesSe"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?megafiles\.se/\w{12}'
- __version__ = "0.01"
- __description__ = """MegaFiles.se hoster plugin"""
- __author_name__ = "t4skforce"
- __author_mail__ = "t4skforce1337[AT]gmail[DOT]com"
+class MegaFilesSe(DeadHoster):
+ __name__ = "MegaFilesSe"
+ __type__ = "hoster"
+ __version__ = "0.02"
- HOSTER_NAME = "megafiles.se"
+ __pattern__ = r'http://(?:www\.)?megafiles\.se/\w{12}'
- OFFLINE_PATTERN = r'<b><font[^>]*>File Not Found</font></b><br><br>'
- FILE_NAME_PATTERN = r'<div[^>]+>\s*<b>(?P<N>[^<]+)</b>\s*</div>'
+ __description__ = """MegaFiles.se hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")]
getInfo = create_getInfo(MegaFilesSe)
diff --git a/module/plugins/hoster/ShareRapidCom.py b/module/plugins/hoster/MegaRapidCz.py
index 5f17a2f62..37732ade6 100644
--- a/module/plugins/hoster/ShareRapidCom.py
+++ b/module/plugins/hoster/MegaRapidCz.py
@@ -13,28 +13,32 @@ def getInfo(urls):
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)
- file_info = parseFileInfo(ShareRapidCom, url, html)
- yield file_info
+ yield parseFileInfo(MegaRapidCz, url, html)
-class ShareRapidCom(SimpleHoster):
- __name__ = "ShareRapidCom"
- __version__ = "0.54"
- __type__ = "hoster"
+class MegaRapidCz(SimpleHoster):
+ __name__ = "MegaRapidCz"
+ __type__ = "hoster"
+ __version__ = "0.55"
__pattern__ = r'http://(?:www\.)?(share|mega)rapid\.cz/soubor/\d+/.+'
__description__ = """MegaRapid.cz hoster plugin"""
- __author_name__ = ("MikyWoW", "zoidberg", "stickell", "Walter Purcaro")
- __author_mail__ = ("mikywow@seznam.cz", "zoidberg@mujmail.cz", "l.stickell@yahoo.it", "vuolter@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("MikyWoW", "mikywow@seznam.cz"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
- FILE_NAME_PATTERN = r'<h1[^>]*><span[^>]*>(?:<a[^>]*>)?(?P<N>[^<]+)'
- FILE_SIZE_PATTERN = r'<td class="i">Velikost:</td>\s*<td class="h"><strong>\s*(?P<S>[0-9.]+) (?P<U>[kKMG])i?B</strong></td>'
+ 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'
- SH_CHECK_TRAFFIC = True
+ CHECK_TRAFFIC = True
LINK_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'
@@ -44,12 +48,13 @@ class ShareRapidCom(SimpleHoster):
def setup(self):
self.chunkLimit = 1
+
def handlePremium(self):
try:
self.html = self.load(self.pyfile.url, decode=True)
except BadHeader, e:
self.account.relogin(self.user)
- self.retry(max_tries=3, reason=str(e))
+ self.retry(wait_time=60, reason=str(e))
m = re.search(self.LINK_PATTERN, self.html)
if m:
@@ -59,8 +64,8 @@ class ShareRapidCom(SimpleHoster):
else:
if re.search(self.ERR_LOGIN_PATTERN, self.html):
self.relogin(self.user)
- self.retry(max_tries=3, reason="User login failed")
+ self.retry(wait_time=60, reason=_("User login failed"))
elif re.search(self.ERR_CREDIT_PATTERN, self.html):
- self.fail("Not enough credit left")
+ self.fail(_("Not enough credit left"))
else:
- self.fail("Download link not found")
+ self.fail(_("Download link not found"))
diff --git a/module/plugins/hoster/MegacrypterCom.py b/module/plugins/hoster/MegacrypterCom.py
index aa167ba30..4034f7d32 100644
--- a/module/plugins/hoster/MegacrypterCom.py
+++ b/module/plugins/hoster/MegacrypterCom.py
@@ -3,27 +3,33 @@
import re
from module.common.json_layer import json_loads, json_dumps
-from module.plugins.hoster.MegaNz import MegaNz
+from module.plugins.hoster.MegaCoNz import MegaCoNz
+
+
+class MegacrypterCom(MegaCoNz):
+ __name__ = "MegacrypterCom"
+ __type__ = "hoster"
+ __version__ = "0.21"
+
+ __pattern__ = r'(https?://\w{0,10}\.?megacrypter\.com/[\w!-]+)'
-class MegacrypterCom(MegaNz):
- __name__ = "MegacrypterCom"
- __type__ = "hoster"
- __pattern__ = r'(https?://[a-z0-9]{0,10}\.?megacrypter\.com/[a-zA-Z0-9!_\-]+)'
- __version__ = "0.2"
__description__ = """Megacrypter.com decrypter plugin"""
- __author_name__ = "GonzaloSR"
- __author_mail__ = "gonzalo@gonzalosr.com"
+ __license__ = "GPLv3"
+ __authors__ = [("GonzaloSR", "gonzalo@gonzalosr.com")]
+
API_URL = "http://megacrypter.com/api"
FILE_SUFFIX = ".crypted"
+
def callApi(self, **kwargs):
""" Dispatch a call to the api, see megacrypter.com/api_doc """
self.logDebug("JSON request: " + json_dumps(kwargs))
- resp = self.load(self.API_URL, post=json_dumps(kwargs))
- self.logDebug("API Response: " + resp)
- return json_loads(resp)
+ res = self.load(self.API_URL, post=json_dumps(kwargs))
+ self.logDebug("API Response: " + res)
+ return json_loads(res)
+
def process(self, pyfile):
# match is guaranteed because plugin was chosen to handle url
diff --git a/module/plugins/hoster/MegareleaseOrg.py b/module/plugins/hoster/MegareleaseOrg.py
index eea265323..60796c1ee 100644
--- a/module/plugins/hoster/MegareleaseOrg.py
+++ b/module/plugins/hoster/MegareleaseOrg.py
@@ -1,34 +1,19 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-class MegareleaseOrg(XFileSharingPro):
- __name__ = "MegareleaseOrg"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?megarelease.org/\w{12}'
- __version__ = "0.01"
- __description__ = """Megarelease.org hoster plugin"""
- __author_name__ = ("derek3x", "stickell")
- __author_mail__ = ("derek3x@vmail.me", "l.stickell@yahoo.it")
+class MegareleaseOrg(DeadHoster):
+ __name__ = "MegareleaseOrg"
+ __type__ = "hoster"
+ __version__ = "0.02"
- HOSTER_NAME = "megarelease.org"
+ __pattern__ = r'https?://(?:www\.)?megarelease\.org/\w{12}'
- FILE_INFO_PATTERN = r'<font color="red">%s/(?P<N>.+)</font> \((?P<S>[^)]+)\)</font>' % __pattern__
+ __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
index f8fa338f3..9d8441c6f 100644
--- a/module/plugins/hoster/MegasharesCom.py
+++ b/module/plugins/hoster/MegasharesCom.py
@@ -1,41 +1,33 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from time import time
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class MegasharesCom(SimpleHoster):
- __name__ = "MegasharesCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?megashares.com/.*'
- __version__ = "0.24"
+ __name__ = "MegasharesCom"
+ __type__ = "hoster"
+ __version__ = "0.27"
+
+ __pattern__ = r'http://(?:www\.)?(d\d{2}\.)?megashares\.com/((index\.php)?\?d\d{2}=|dl/)\w+'
+
__description__ = """Megashares.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
- FILE_NAME_PATTERN = r'<h1 class="black xxl"[^>]*title="(?P<N>[^"]+)">'
- FILE_SIZE_PATTERN = r'<strong><span class="black">Filesize:</span></strong> (?P<S>[0-9.]+) (?P<U>[kKMG])i?B<br />'
- OFFLINE_PATTERN = r'<dd class="red">(Invalid Link Request|Link has been deleted)'
+
+ 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+).*\s*You have\s*<[^>]*>\s*([0-9.]+) ([kKMG]i?B)'
- PASSPORT_RENEW_PATTERN = r'Your download passport will renew in\s*<strong>(\d+)</strong>:<strong>(\d+)</strong>:<strong>(\d+)</strong>'
+
+ 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 = "([^"]+)";'
@@ -44,69 +36,74 @@ class MegasharesCom(SimpleHoster):
def setup(self):
self.resumeDownload = True
- self.multiDL = self.premium
+ self.multiDL = self.premium
+
def handlePremium(self):
self.handleDownload(True)
- def handleFree(self):
- self.html = self.load(self.pyfile.url, decode=True)
+ def handleFree(self):
if self.NO_SLOTS_PATTERN in self.html:
self.retry(wait_time=5 * 60)
- self.getFileInfo()
- # if self.pyfile.size > 576716800:
- # self.fail("This file is too large for free download")
-
- # Reactivate passport if needed
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 _ in xrange(5):
+ 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?secgfx=gfx&random_num=%s" % random_num)
- self.logInfo("Reactivating passport %s: %s %s" % (passport_num, random_num, verifyinput))
+ 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))
- url = ("http://d01.megashares.com%s&rs=check_passport_renewal" % request_uri +
- "&rsargs[]=%s&rsargs[]=%s&rsargs[]=%s" % (verifyinput, random_num, passport_num) +
- "&rsargs[]=replace_sec_pprenewal&rsrnd=%s" % str(int(time() * 1000)))
- self.logDebug(url)
- response = self.load(url)
+ 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 response:
+ if 'Thank you for reactivating your passport.' in res:
self.correctCaptcha()
self.retry()
else:
self.invalidCaptcha()
else:
- self.fail("Failed to reactivate passport")
+ 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)
+ 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 ** {'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))
+ 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:
- m = re.search(self.PASSPORT_RENEW_PATTERN, self.html)
- renew = m.group(1) + m.group(2) + m.group(3) * 60 * 60 if m else 10 * 60
- self.retry(max_tries=15, wait_time=renew, reason="Unable to get passport")
+ 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')
+ msg = _('%s download URL' % ('Premium' if premium else 'Free'))
if m is None:
- self.parseError(msg)
+ self.error(msg)
download_url = m.group(1)
self.logDebug("%s: %s" % (msg, download_url))
diff --git a/module/plugins/hoster/MegauploadCom.py b/module/plugins/hoster/MegauploadCom.py
new file mode 100644
index 000000000..7f51a8a46
--- /dev/null
+++ b/module/plugins/hoster/MegauploadCom.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
new file mode 100644
index 000000000..24905ce62
--- /dev/null
+++ b/module/plugins/hoster/MegavideoCom.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
index 266e9dc55..9bb63701c 100644
--- a/module/plugins/hoster/MovReelCom.py
+++ b/module/plugins/hoster/MovReelCom.py
@@ -1,25 +1,23 @@
# -*- coding: utf-8 -*-
-#import re
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-#from pycurl import FOLLOWLOCATION, LOW_SPEED_TIME
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+class MovReelCom(XFSHoster):
+ __name__ = "MovReelCom"
+ __type__ = "hoster"
+ __version__ = "1.24"
+
+ __pattern__ = r'http://(?:www\.)?movreel\.com/\w{12}'
-class MovReelCom(XFileSharingPro):
- __name__ = "MovReelCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?movreel.com/.*'
- __version__ = "1.20"
__description__ = """MovReel.com hoster plugin"""
- __author_name__ = "JorisV83"
- __author_mail__ = "jorisv83-pyload@yahoo.com"
+ __license__ = "GPLv3"
+ __authors__ = [("JorisV83", "jorisv83-pyload@yahoo.com")]
+
- HOSTER_NAME = "movreel.com"
+ HOSTER_DOMAIN = "movreel.com"
- FILE_INFO_PATTERN = r'<h3>(?P<N>.+?) <small><sup>(?P<S>[\d.]+) (?P<U>..)</sup> </small></h3>'
- OFFLINE_PATTERN = r'<b>File Not Found</b><br><br>'
- LINK_PATTERN = r'<a href="(http://[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/.*)">Download Link</a>'
+ LINK_PATTERN = r'<a href="([^"]+)">Download Link'
getInfo = create_getInfo(MovReelCom)
diff --git a/module/plugins/hoster/MultiDebridCom.py b/module/plugins/hoster/MultiDebridCom.py
deleted file mode 100644
index 71f3df908..000000000
--- a/module/plugins/hoster/MultiDebridCom.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
-
-import re
-
-from module.plugins.Hoster import Hoster
-from module.common.json_layer import json_loads
-
-
-class MultiDebridCom(Hoster):
- __name__ = "MultiDebridCom"
- __version__ = "0.03"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/dl/'
- __description__ = """Multi-debrid.com hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- def setup(self):
- self.chunkLimit = -1
- self.resumeDownload = True
-
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "Multi-debrid.com")
- self.fail("No Multi-debrid.com account provided")
- else:
- self.logDebug("Original URL: %s" % pyfile.url)
- page = self.req.load('http://multi-debrid.com/api.php',
- get={'user': self.user, 'pass': self.account.getAccountData(self.user)['password'],
- 'link': pyfile.url})
- self.logDebug("JSON data: " + page)
- page = json_loads(page)
- if page['status'] != 'ok':
- self.fail('Unable to unrestrict link')
- new_url = page['link']
-
- if new_url != pyfile.url:
- self.logDebug("Unrestricted URL: " + new_url)
-
- self.download(new_url, disposition=True)
diff --git a/module/plugins/hoster/MultishareCz.py b/module/plugins/hoster/MultishareCz.py
index c2fbaf46e..adbae2da4 100644
--- a/module/plugins/hoster/MultishareCz.py
+++ b/module/plugins/hoster/MultishareCz.py
@@ -1,80 +1,65 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from random import random
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class MultishareCz(SimpleHoster):
- __name__ = "MultishareCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?multishare.cz/stahnout/(?P<ID>\d+).*'
- __version__ = "0.34"
+ __name__ = "MultishareCz"
+ __type__ = "hoster"
+ __version__ = "0.36"
+
+ __pattern__ = r'http://(?:www\.)?multishare\.cz/stahnout/(?P<ID>\d+)'
+
__description__ = """MultiShare.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ SIZE_REPLACEMENTS = [('&nbsp;', '')]
- FILE_INFO_PATTERN = ur'(?:<li>Název|Soubor): <strong>(?P<N>[^<]+)</strong><(?:/li><li|br)>Velikost: <strong>(?P<S>[^<]+)</strong>'
+ 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>'
- FILE_SIZE_REPLACEMENTS = [('&nbsp;', '')]
-
- def process(self, pyfile):
- msurl = re.match(self.__pattern__, pyfile.url)
- if msurl:
- self.fileID = msurl.group('ID')
- self.html = self.load(pyfile.url, decode=True)
- self.getFileInfo()
-
- if self.premium:
- self.handlePremium()
- else:
- self.handleFree()
- else:
- self.handleOverriden()
+
def handleFree(self):
- self.download("http://www.multishare.cz/html/download_free.php?ID=%s" % self.fileID)
+ self.download("http://www.multishare.cz/html/download_free.php?ID=%s" % self.info['pattern']['ID'])
+
def handlePremium(self):
if not self.checkCredit():
- self.logWarning("Not enough credit left to download file")
+ self.logWarning(_("Not enough credit left to download file"))
self.resetAccount()
- self.download("http://www.multishare.cz/html/download_premium.php?ID=%s" % self.fileID)
+ self.download("http://www.multishare.cz/html/download_premium.php?ID=%s" % self.info['pattern']['ID'])
- def handleOverriden(self):
- if not self.premium:
- self.fail("Only premium users can download from other hosters")
+ def handleMulti(self):
self.html = self.load('http://www.multishare.cz/html/mms_ajax.php', post={"link": self.pyfile.url}, decode=True)
- self.getFileInfo()
+
+ self.checkInfo()
if not self.checkCredit():
- self.fail("Not enough credit left to download file")
+ self.fail(_("Not enough credit left to download file"))
- url = "http://dl%d.mms.multishare.cz/html/mms_process.php" % round(random() * 10000 * random())
+ url = "http://dl%d.mms.multishare.cz/html/mms_process.php" % round(random() * 10000 * random())
params = {"u_ID": self.acc_info['u_ID'], "u_hash": self.acc_info['u_hash'], "link": self.pyfile.url}
+
self.logDebug(url, params)
+
+ self.link = True
self.download(url, get=params)
+
def checkCredit(self):
self.acc_info = self.account.getAccountInfo(self.user, True)
- self.logInfo("User %s has %i MB left" % (self.user, self.acc_info['trafficleft'] / 1024))
+
+ self.logInfo(_("User %s has %i MB left") % (self.user, self.acc_info['trafficleft'] / 1024))
return self.pyfile.size / 1024 <= self.acc_info['trafficleft']
diff --git a/module/plugins/hoster/MyfastfileCom.py b/module/plugins/hoster/MyfastfileCom.py
new file mode 100644
index 000000000..b5b9ec820
--- /dev/null
+++ b/module/plugins/hoster/MyfastfileCom.py
@@ -0,0 +1,42 @@
+# -*- 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.07"
+
+ __pattern__ = r'http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/dl/'
+
+ __description__ = """Myfastfile.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
+
+ def setup(self):
+ self.chunkLimit = -1
+ self.resumeDownload = True
+
+
+ def handlePremium(self):
+ self.logDebug("Original URL: %s" % self.pyfile.url)
+
+ page = self.load('http://myfastfile.com/api.php',
+ get={'user': self.user, 'pass': self.account.getAccountData(self.user)['password'],
+ 'link': self.pyfile.url})
+ self.logDebug("JSON data: " + page)
+ page = json_loads(page)
+ if page['status'] != 'ok':
+ self.fail(_("Unable to unrestrict link"))
+ self.link = page['link']
+
+ if self.link != self.pyfile.url:
+ self.logDebug("Unrestricted URL: " + self.link)
+
+
+getInfo = create_getInfo(MyfastfileCom)
diff --git a/module/plugins/hoster/MyvideoDe.py b/module/plugins/hoster/MyvideoDe.py
index 21d95d092..8af4a9a61 100644
--- a/module/plugins/hoster/MyvideoDe.py
+++ b/module/plugins/hoster/MyvideoDe.py
@@ -1,18 +1,22 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.Hoster import Hoster
from module.unescape import unescape
class MyvideoDe(Hoster):
- __name__ = "MyvideoDe"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?myvideo.de/watch/'
- __version__ = "0.9"
+ __name__ = "MyvideoDe"
+ __type__ = "hoster"
+ __version__ = "0.90"
+
+ __pattern__ = r'http://(?:www\.)?myvideo\.de/watch/'
+
__description__ = """Myvideo.de hoster plugin"""
- __author_name__ = "spoob"
- __author_mail__ = "spoob@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org")]
+
def process(self, pyfile):
self.pyfile = pyfile
@@ -20,19 +24,23 @@ class MyvideoDe(Hoster):
pyfile.name = self.get_file_name()
self.download(self.get_file_url())
+
def download_html(self):
self.html = self.load(self.pyfile.url)
+
def get_file_url(self):
videoId = re.search(r"addVariable\('_videoid','(.*)'\);p.addParam\('quality'", self.html).group(1)
videoServer = re.search("rel='image_src' href='(.*)thumbs/.*' />", self.html).group(1)
file_url = videoServer + videoId + ".flv"
return file_url
+
def get_file_name(self):
- file_name_pattern = r"<h1 class='globalHd'>(.*)</h1>"
+ file_name_pattern = r'<h1 class=\'globalHd\'>(.*)</h1>'
return unescape(re.search(file_name_pattern, self.html).group(1).replace("/", "") + '.flv')
+
def file_exists(self):
self.download_html()
self.load(str(self.pyfile.url), cookies=False, just_header=True)
diff --git a/module/plugins/hoster/NahrajCz.py b/module/plugins/hoster/NahrajCz.py
new file mode 100644
index 000000000..6b5699408
--- /dev/null
+++ b/module/plugins/hoster/NahrajCz.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
index 396e207a0..21d4e3e3d 100644
--- a/module/plugins/hoster/NarodRu.py
+++ b/module/plugins/hoster/NarodRu.py
@@ -1,51 +1,42 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from random import random
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class NarodRu(SimpleHoster):
- __name__ = "NarodRu"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?narod(\.yandex)?\.ru/(disk|start/[0-9]+\.\w+-narod\.yandex\.ru)/(?P<ID>\d+)/.+'
- __version__ = "0.1"
+ __name__ = "NarodRu"
+ __type__ = "hoster"
+ __version__ = "0.11"
+
+ __pattern__ = r'http://(?:www\.)?narod(\.yandex)?\.ru/(disk|start/\d+\.\w+-narod\.yandex\.ru)/(?P<ID>\d+)/.+'
+
__description__ = """Narod.ru hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<dt class="name">(?:<[^<]*>)*(?P<N>[^<]+)</dt>'
- FILE_SIZE_PATTERN = r'<dd class="size">(?P<S>\d[^<]*)</dd>'
+
+ 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>|Ѐайл уЎалеМ с сервОса|ЗакПМчОлся срПк храМеМОя файла\.'
- FILE_SIZE_REPLACEMENTS = [(u'КБ', 'KB'), (u'МБ', 'MB'), (u'ГБ', 'GB')]
- FILE_URL_REPLACEMENTS = [("narod.yandex.ru/", "narod.ru/"),
- (r"/start/[0-9]+\.\w+-narod\.yandex\.ru/([0-9]{6,15})/\w+/(\w+)", r"/disk/\1/\2")]
+ 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_PATTERN = r'<a class="h-link" rel="yandex_bar" href="(.+?)">'
+
def handleFree(self):
- for _ in xrange(5):
+ 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.parseError('Captcha')
+ self.error(_("Captcha"))
post_data = {"action": "sendcapcha"}
captcha_url, post_data['key'] = m.groups()
post_data['rep'] = self.decryptCaptcha(captcha_url)
@@ -59,11 +50,10 @@ class NarodRu(SimpleHoster):
elif u'<b class="error-msg"><strong>ОшОблОсь?</strong>' in self.html:
self.invalidCaptcha()
else:
- self.parseError('Download link')
+ self.error(_("Download link"))
else:
- self.fail("No valid captcha code entered")
+ self.fail(_("No valid captcha code entered"))
- self.logDebug('Download link: ' + url)
self.download(url)
diff --git a/module/plugins/hoster/NetloadIn.py b/module/plugins/hoster/NetloadIn.py
index 2baeed5da..f5c5ee802 100644
--- a/module/plugins/hoster/NetloadIn.py
+++ b/module/plugins/hoster/NetloadIn.py
@@ -1,17 +1,20 @@
# -*- coding: utf-8 -*-
import re
+
+from urlparse import urljoin
from time import sleep, time
-from module.plugins.Hoster import Hoster
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
def getInfo(urls):
## returns list of tupels (name, size (in bytes), status (see FileDatabase), url)
- apiurl = "http://api.netload.in/info.php?auth=Zf9SnQh9WiReEsb18akjvQGqT0I830e8&bz=1&md5=1&file_id="
+ apiurl = "http://api.netload.in/info.php"
id_regex = re.compile(NetloadIn.__pattern__)
urls_per_query = 80
@@ -22,13 +25,19 @@ def getInfo(urls):
if match:
ids = ids + match.group(1) + ";"
- api = getURL(apiurl + ids, decode=True)
+ api = getURL(apiurl,
+ get={'auth' : "Zf9SnQh9WiReEsb18akjvQGqT0I830e8",
+ 'bz' : 1,
+ 'md5' : 1,
+ 'file_id': ids},
+ decode=True)
if api is None or len(api) < 10:
- print "Netload prefetch: failed "
+ self.logDebug("Prefetch failed")
return
+
if api.find("unknown_auth") >= 0:
- print "Netload prefetch: Outdated auth code "
+ self.logDebug("Outdated auth code")
return
result = []
@@ -36,36 +45,48 @@ def getInfo(urls):
for i, r in enumerate(api.splitlines()):
try:
tmp = r.split(";")
+
try:
size = int(tmp[2])
- except:
+ except Exception:
size = 0
- result.append((tmp[1], size, 2 if tmp[3] == "online" else 1, chunk[i]))
- except:
- print "Netload prefetch: Error while processing response: "
- print r
+
+ result.append((tmp[1], size, 2 if tmp[3] == "online" else 1, chunk[i] ))
+
+ except Exception:
+ self.logDebug("Error while processing response: %s" % r)
yield result
class NetloadIn(Hoster):
- __name__ = "NetloadIn"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:[^/]*\.)?netload\.in/(?:datei(.*?)(?:\.htm|/)|index.php?id=10&file_id=)'
- __version__ = "0.45"
+ __name__ = "NetloadIn"
+ __type__ = "hoster"
+ __version__ = "0.47"
+
+ __pattern__ = r'https?://(?:[^/]*\.)?netload\.in/(?:datei(.*?)(?:\.htm|/)|index\.php?id=10&file_id=)'
+
__description__ = """Netload.in hoster plugin"""
- __author_name__ = ("spoob", "RaNaN", "Gregy")
- __author_mail__ = ("spoob@pyload.org", "ranan@pyload.org", "gregy@gregy.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org"),
+ ("RaNaN", "ranan@pyload.org"),
+ ("Gregy", "gregy@gregy.cz")]
+
def setup(self):
self.multiDL = self.resumeDownload = self.premium
+
def process(self, pyfile):
self.url = pyfile.url
+
self.prepare()
+
pyfile.setStatus("downloading")
+
self.proceed(self.url)
+
def prepare(self):
self.download_api_data()
@@ -73,8 +94,10 @@ class NetloadIn(Hoster):
self.pyfile.name = self.api_data['filename']
if self.premium:
- self.logDebug("Netload: Use Premium Account")
- settings = self.load("http://www.netload.in/index.php?id=2&lang=en")
+ self.logDebug("Use Premium Account")
+
+ settings = self.load("http://www.netload.in/index.php", get={'id': 2, 'lang': "en"})
+
if '<option value="2" selected="selected">Direkter Download' in settings:
self.logDebug("Using direct download")
return True
@@ -84,13 +107,14 @@ class NetloadIn(Hoster):
if self.download_html():
return True
else:
- self.fail("Failed")
+ self.fail(_("Failed"))
return False
+
def download_api_data(self, n=0):
- url = self.url
+ url = self.url
id_regex = re.compile(self.__pattern__)
- match = id_regex.search(url)
+ match = id_regex.search(url)
if match:
#normalize url
@@ -101,23 +125,26 @@ class NetloadIn(Hoster):
return
apiurl = "http://api.netload.in/info.php"
- src = self.load(apiurl, cookies=False,
+ html = self.load(apiurl, cookies=False,
get={"file_id": match.group(1), "auth": "Zf9SnQh9WiReEsb18akjvQGqT0I830e8", "bz": "1",
"md5": "1"}, decode=True).strip()
- if not src and n <= 3:
+ if not html and n <= 3:
sleep(0.2)
self.download_api_data(n + 1)
return
- self.logDebug("Netload: APIDATA: " + src)
+ self.logDebug("APIDATA: " + html)
+
self.api_data = {}
- if src and ";" in src and src not in ("unknown file_data", "unknown_server_data", "No input file specified."):
- lines = src.split(";")
- self.api_data['exists'] = True
- self.api_data['fileid'] = lines[0]
+
+ if html and ";" in html and html not in ("unknown file_data", "unknown_server_data", "No input file specified."):
+ lines = html.split(";")
+ self.api_data['exists'] = True
+ self.api_data['fileid'] = lines[0]
self.api_data['filename'] = lines[1]
- self.api_data['size'] = lines[2]
- self.api_data['status'] = lines[3]
+ self.api_data['size'] = lines[2]
+ self.api_data['status'] = lines[3]
+
if self.api_data['status'] == "online":
self.api_data['checksum'] = lines[4].strip()
else:
@@ -128,20 +155,34 @@ class NetloadIn(Hoster):
else:
self.api_data = False
+
def final_wait(self, page):
wait_time = self.get_wait_time(page)
+
self.setWait(wait_time)
- self.logDebug("Netload: final wait %d seconds" % wait_time)
+
+ self.logDebug("Final wait %d seconds" % wait_time)
+
self.wait()
+
self.url = self.get_file_url(page)
+
+ def check_free_wait(self,page):
+ if ">An access request has been made from IP address <" in page:
+ self.wantReconnect = True
+ self.setWait(self.get_wait_time(page) or 30)
+ self.wait()
+ return True
+ else:
+ return False
+
+
def download_html(self):
- self.logDebug("Netload: Entering download_html")
page = self.load(self.url, decode=True)
- t = time() + 30
if "/share/templates/download_hddcrash.tpl" in page:
- self.logError("Netload HDD Crash")
+ self.logError(_("Netload HDD Crash"))
self.fail(_("File temporarily not available"))
if not self.api_data:
@@ -150,105 +191,104 @@ class NetloadIn(Hoster):
if "* The file was deleted" in page:
self.offline()
- name = re.search(r'class="dl_first_filename">([^<]+)', page, re.MULTILINE)
- # the found filename is not truncated
+ name = re.search(r'class="dl_first_filename">([^<]+)', page, re.M)
+ # the found filename is not truncated
if name:
name = name.group(1).strip()
if not name.endswith(".."):
self.pyfile.name = name
captchawaited = False
- for i in xrange(10):
+ for i in xrange(5):
if not page:
page = self.load(self.url)
t = time() + 30
if "/share/templates/download_hddcrash.tpl" in page:
- self.logError("Netload HDD Crash")
+ self.logError(_("Netload HDD Crash"))
self.fail(_("File temporarily not available"))
- self.logDebug("Netload: try number %d " % i)
+ self.logDebug("Try number %d " % i)
if ">Your download is being prepared.<" in page:
- self.logDebug("Netload: We will prepare your download")
+ self.logDebug("We will prepare your download")
self.final_wait(page)
return True
- if ">An access request has been made from IP address <" in page:
- wait = self.get_wait_time(page)
- if not wait:
- self.logDebug("Netload: Wait was 0 setting 30")
- wait = 30 * 60
- self.logInfo(_("Netload: waiting between downloads %d s." % wait))
- self.wantReconnect = True
- self.setWait(wait)
- self.wait()
- return self.download_html()
-
- self.logDebug("Netload: Trying to find captcha")
+ self.logDebug("Trying to find captcha")
try:
- url_captcha_html = "http://netload.in/" + re.search('(index.php\?id=10&amp;.*&amp;captcha=1)',
- page).group(1).replace("amp;", "")
- except:
+ url_captcha_html = re.search(r'(index.php\?id=10&amp;.*&amp;captcha=1)', page).group(1).replace("amp;", "")
+
+ except Exception, e:
+ self.logDebug("Exception during Captcha regex: %s" % e.message)
page = None
- continue
- try:
- page = self.load(url_captcha_html, cookies=True)
- captcha_url = "http://netload.in/" + re.search('(share/includes/captcha.php\?t=\d*)', page).group(1)
- except:
- self.logDebug("Netload: Could not find captcha, try again from beginning")
- captchawaited = False
- continue
-
- file_id = re.search('<input name="file_id" type="hidden" value="(.*)" />', page).group(1)
- if not captchawaited:
- wait = self.get_wait_time(page)
- if i == 0:
- self.pyfile.waitUntil = time() # dont wait contrary to time on website
- else:
- self.pyfile.waitUntil = t
- self.logInfo(_("Netload: waiting for captcha %d s.") % (self.pyfile.waitUntil - time()))
- #self.setWait(wait)
+ else:
+ url_captcha_html = urljoin("http://netload.in/", url_captcha_html)
+ break
+
+ self.html = self.load(url_captcha_html)
+
+ recaptcha = ReCaptcha(self)
+
+ for _i in xrange(5):
+ challenge, response = recaptcha.challenge()
+
+ response_page = self.load("http://www.netload.in/index.php?id=10",
+ post={'captcha_check' : '1',
+ 'recaptcha_challenge_field': challenge,
+ 'recaptcha_response_field' : response,
+ 'file_id' : self.api_data['fileid'],
+ 'Download_Next' : ''})
+ if "Orange_Link" in response_page:
+ break
+
+ if self.check_free_wait(response_page):
+ self.logDebug("Had to wait for next free slot, trying again")
+ return self.download_html()
+
+ else:
+ download_url = self.get_file_url(response_page)
+ self.logDebug("Download URL after get_file: " + download_url)
+ if not download_url.startswith("http://"):
+ self.error("download url: %s" % download_url)
self.wait()
- captchawaited = True
- captcha = self.decryptCaptcha(captcha_url)
- page = self.load("http://netload.in/index.php?id=10", post={"file_id": file_id, "captcha_check": captcha},
- cookies=True)
+ self.url = download_url
+ return True
- return False
def get_file_url(self, page):
try:
- file_url_pattern = r"<a class=\"Orange_Link\" href=\"(http://.+)\".?>Or click here"
+ file_url_pattern = r'<a class="Orange_Link" href="(http://.+)".?>Or click here'
attempt = re.search(file_url_pattern, page)
if attempt is not None:
return attempt.group(1)
else:
- self.logDebug("Netload: Backup try for final link")
- file_url_pattern = r"<a href=\"(.+)\" class=\"Orange_Link\">Click here"
+ self.logDebug("Backup try for final link")
+ file_url_pattern = r'<a href="(.+)" class="Orange_Link">Click here'
attempt = re.search(file_url_pattern, page)
return "http://netload.in/" + attempt.group(1)
- except:
- self.logDebug("Netload: Getting final link failed")
+
+ except Exception, e:
+ self.logDebug("Getting final link failed", e.message)
return None
+
def get_wait_time(self, page):
- wait_seconds = int(re.search(r"countdown\((.+),'change\(\)'\)", page).group(1)) / 100
- return wait_seconds
+ return int(re.search(r"countdown\((.+),'change\(\)'\)", page).group(1)) / 100
- def proceed(self, url):
- self.logDebug("Netload: Downloading..")
+ def proceed(self, url):
self.download(url, disposition=True)
- check = self.checkDownload({"empty": re.compile(r"^$"), "offline": re.compile("The file was deleted")})
-
+ check = self.checkDownload({'empty' : re.compile(r'^$'),
+ 'offline': re.compile("The file was deleted")})
if check == "empty":
self.logInfo(_("Downloaded File was empty"))
self.retry()
+
elif check == "offline":
self.offline()
diff --git a/module/plugins/hoster/NoPremiumPl.py b/module/plugins/hoster/NoPremiumPl.py
new file mode 100644
index 000000000..f4f7ba56a
--- /dev/null
+++ b/module/plugins/hoster/NoPremiumPl.py
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.SimpleHoster import SimpleHoster
+from module.common.json_layer import json_loads as loads
+
+
+class NoPremiumPl(SimpleHoster):
+ __name__ = "NoPremiumPl"
+ __version__ = "0.01"
+ __type__ = "hoster"
+
+ __pattern__ = r"https?://direct\.nopremium\.pl.*"
+ __description__ = "NoPremium.pl 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"
+ }
+
+ _usr = False
+ _pwd = False
+
+ def setup(self):
+ self.resumeDownload = True
+ self.multiDL = True
+
+ def get_username_password(self):
+ if not self.account:
+ self.fail(_("Please enter your %s account or deactivate this plugin") % "NoPremium.pl")
+ else:
+ self._usr = self.account.getAccountData(self.user).get('usr')
+ self._pwd = self.account.getAccountData(self.user).get('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 process(self, pyfile):
+ self.get_username_password()
+ try:
+ data = self.runFileQuery(pyfile.url, 'fileinfo')
+ except Exception:
+ self.logDebug("runFileQuery error")
+ self.tempOffline()
+
+ try:
+ parsed = 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 webiste \
+ directly. Update this plugin." % parsed["hosting"])
+
+ pyfile.name = parsed["filename"]
+ pyfile.size = parsed["filesize"]
+
+ try:
+ result_dl = self.runFileQuery(pyfile.url, 'filedownload')
+ except Exception:
+ self.logDebug("runFileQuery error #2")
+ self.tempOffline()
+
+ self.download(result_dl, disposition=True)
diff --git a/module/plugins/hoster/NosuploadCom.py b/module/plugins/hoster/NosuploadCom.py
index ff7628c46..8a03d7090 100644
--- a/module/plugins/hoster/NosuploadCom.py
+++ b/module/plugins/hoster/NosuploadCom.py
@@ -2,24 +2,29 @@
import re
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class NosuploadCom(XFileSharingPro):
- __name__ = "NosuploadCom"
- __type__ = "hoster"
- __version__ = "0.1"
+class NosuploadCom(XFSHoster):
+ __name__ = "NosuploadCom"
+ __type__ = "hoster"
+ __version__ = "0.31"
+
__pattern__ = r'http://(?:www\.)?nosupload\.com/\?d=\w{12}'
+
__description__ = """Nosupload.com hoster plugin"""
- __author_name__ = "igel"
- __author_mail__ = "igelkun@myopera.com"
+ __license__ = "GPLv3"
+ __authors__ = [("igel", "igelkun@myopera.com")]
+
- HOSTER_NAME = "nosupload.com"
+ HOSTER_DOMAIN = "nosupload.com"
- FILE_SIZE_PATTERN = r'<p><strong>Size:</strong> (?P<S>[0-9\.]+) (?P<U>[kKMG]?B)</p>'
+ 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()
@@ -27,8 +32,8 @@ class NosuploadCom(XFileSharingPro):
# stage2: wait some time and press the "Download File" button
data = self.getPostParameters()
- wait_time = re.search(self.WAIT_PATTERN, self.html, re.MULTILINE | re.DOTALL).group(1)
- self.logDebug("hoster told us to wait %s seconds" % wait_time)
+ 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)
diff --git a/module/plugins/hoster/NovafileCom.py b/module/plugins/hoster/NovafileCom.py
index 9b4d50907..9754ceed1 100644
--- a/module/plugins/hoster/NovafileCom.py
+++ b/module/plugins/hoster/NovafileCom.py
@@ -1,30 +1,31 @@
# -*- coding: utf-8 -*-
-
-# Test links (random.bin):
+#
+# Test links:
# http://novafile.com/vfun4z6o2cit
# http://novafile.com/s6zrr5wemuz4
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+class NovafileCom(XFSHoster):
+ __name__ = "NovafileCom"
+ __type__ = "hoster"
+ __version__ = "0.05"
-class NovafileCom(XFileSharingPro):
- __name__ = "NovafileCom"
- __type__ = "hoster"
__pattern__ = r'http://(?:www\.)?novafile\.com/\w{12}'
- __version__ = "0.02"
+
__description__ = """Novafile.com hoster plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
- HOSTER_NAME = "novafile.com"
- FILE_SIZE_PATTERN = r'<div class="size">(?P<S>.+?)</div>'
+ HOSTER_DOMAIN = "novafile.com"
+
ERROR_PATTERN = r'class="alert[^"]*alert-separate"[^>]*>\s*(?:<p>)?(.*?)\s*</'
- LINK_PATTERN = r'<a href="(http://s\d+\.novafile\.com/.*?)" class="btn btn-green">Download File</a>'
- WAIT_PATTERN = r'<p>Please wait <span id="count"[^>]*>(\d+)</span> seconds</p>'
+ WAIT_PATTERN = r'<p>Please wait <span id="count"[^>]*>(\d+)</span> seconds</p>'
- def setup(self):
- self.multiDL = False
+ 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/NowDownloadEu.py b/module/plugins/hoster/NowDownloadEu.py
deleted file mode 100644
index cf4f46805..000000000
--- a/module/plugins/hoster/NowDownloadEu.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-from module.utils import fixup
-
-
-class NowDownloadEu(SimpleHoster):
- __name__ = "NowDownloadEu"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?nowdownload\.(ch|co|eu|sx)/(dl/|download\.php\?id=)(?P<ID>\w+)'
- __version__ = "0.05"
- __description__ = """NowDownload.ch hoster plugin"""
- __author_name__ = ("godofdream", "Walter Purcaro")
- __author_mail__ = ("soilfiction@gmail.com", "vuolter@gmail.com")
-
- FILE_INFO_PATTERN = r'Downloading</span> <br> (?P<N>.*) (?P<S>[0-9,.]+) (?P<U>[kKMG])i?B </h4>'
- OFFLINE_PATTERN = r'(This file does not exist!)'
-
- TOKEN_PATTERN = r'"(/api/token\.php\?token=[a-z0-9]+)"'
- CONTINUE_PATTERN = r'"(/dl2/[a-z0-9]+/[a-z0-9]+)"'
- WAIT_PATTERN = r'\.countdown\(\{until: \+(\d+),'
- LINK_PATTERN = r'"(http://f\d+\.nowdownload\.ch/dl/[a-z0-9]+/[a-z0-9]+/[^<>"]*?)"'
-
- FILE_NAME_REPLACEMENTS = [("&#?\w+;", fixup), (r'<[^>]*>', '')]
-
-
- def setup(self):
- self.multiDL = self.resumeDownload = True
- self.chunkLimit = -1
-
- def handleFree(self):
- 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.fail('Plugin out of Date')
-
- m = re.search(self.WAIT_PATTERN, self.html)
- if m:
- wait = int(m.group(1))
- else:
- wait = 60
-
- baseurl = "http://www.nowdownload.ch"
- 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_PATTERN, self.html)
- if url is None:
- self.fail('Download Link not Found (Plugin out of Date?)')
- self.logDebug('Download link: ' + str(url.group(1)))
- self.download(str(url.group(1)))
-
-
-getInfo = create_getInfo(NowDownloadEu)
diff --git a/module/plugins/hoster/NowDownloadSx.py b/module/plugins/hoster/NowDownloadSx.py
new file mode 100644
index 000000000..d2ae08954
--- /dev/null
+++ b/module/plugins/hoster/NowDownloadSx.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+from module.utils import fixup
+
+
+class NowDownloadSx(SimpleHoster):
+ __name__ = "NowDownloadSx"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __pattern__ = r'http://(?:www\.)?nowdownload\.(at|ch|co|eu|sx)/(dl/|download\.php\?id=)\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_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):
+ 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_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
new file mode 100644
index 000000000..d0777ca4b
--- /dev/null
+++ b/module/plugins/hoster/NowVideoSx.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class NowVideoSx(SimpleHoster):
+ __name__ = "NowVideoSx"
+ __type__ = "hoster"
+ __version__ = "0.08"
+
+ __pattern__ = r'http://(?:www\.)?nowvideo\.(at|ch|co|eu|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):
+ 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/OboomCom.py b/module/plugins/hoster/OboomCom.py
index b6eeba3c8..588d8f64a 100644
--- a/module/plugins/hoster/OboomCom.py
+++ b/module/plugins/hoster/OboomCom.py
@@ -1,53 +1,79 @@
# -*- coding: utf-8 -*-
-
-# Test link:
+#
+# Test links:
# https://www.oboom.com/B7CYZIEB/10Mio.dat
import re
+from module.common.json_layer import json_loads
from module.plugins.Hoster import Hoster
from module.plugins.internal.CaptchaService import ReCaptcha
-from module.common.json_layer import json_loads
class OboomCom(Hoster):
- __name__ = "OboomCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?oboom\.com/(#(id=|/)?)?(?P<ID>[A-Z0-9]{8})'
- __version__ = "0.1"
+ __name__ = "OboomCom"
+ __type__ = "hoster"
+ __version__ = "0.30"
+
+ __pattern__ = r'https?://(?:www\.)?oboom\.com/(#(id=|/)?)?(?P<ID>\w{8})'
+
__description__ = """oboom.com hoster plugin"""
- __author_name__ = "stanley"
- __author_mail__ = "stanley.foerster@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("stanley", "stanley.foerster@gmail.com")]
+
RECAPTCHA_KEY = "6LdqpO0SAAAAAJGHXo63HyalP7H4qlRs_vff0kJX"
+ def setup(self):
+ self.chunkLimit = 1
+ self.multiDL = self.resumeDownload = self.premium
+
+
+ def process(self, pyfile):
+ self.pyfile.url.replace(".com/#id=", ".com/#")
+ self.pyfile.url.replace(".com/#/", ".com/#")
+ self.getFileId(self.pyfile.url)
+ self.getSessionToken()
+ self.getFileInfo(self.sessionToken, self.fileId)
+ self.pyfile.name = self.fileName
+ self.pyfile.size = self.fileSize
+ if not self.premium:
+ self.solveCaptcha()
+ self.getDownloadTicket()
+ self.download("https://%s/1.0/dlh" % self.downloadDomain, get={"ticket": self.downloadTicket, "http_errors": 0})
+
+
def loadUrl(self, url, get=None):
if get is None:
get = dict()
return json_loads(self.load(url, get, decode=True))
+
def getFileId(self, url):
self.fileId = re.match(OboomCom.__pattern__, url).group('ID')
+
def getSessionToken(self):
if self.premium:
accountInfo = self.account.getAccountInfo(self.user, True)
if "session" in accountInfo:
self.sessionToken = accountInfo['session']
else:
- self.fail("Could not retrieve premium session")
+ self.fail(_("Could not retrieve premium session"))
else:
apiUrl = "https://www.oboom.com/1.0/guestsession"
result = self.loadUrl(apiUrl)
if result[0] == 200:
self.sessionToken = result[1]
else:
- self.fail("Could not retrieve token for guest session. Error code %s" % result[0])
+ self.fail(_("Could not retrieve token for guest session. Error code: %s") % result[0])
+
def solveCaptcha(self):
recaptcha = ReCaptcha(self)
- for _ in xrange(5):
+
+ for _i in xrange(5):
challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
apiUrl = "https://www.oboom.com/1.0/download/ticket"
params = {"recaptcha_challenge_field": challenge,
@@ -63,23 +89,26 @@ class OboomCom(Hoster):
self.setWait(30)
self.wait()
break
+
elif result[0] == 400:
if result[1] == "incorrect-captcha-sol":
self.invalidCaptcha()
elif result[1] == "captcha-timeout":
self.invalidCaptcha()
elif result[1] == "forbidden":
- self.retry(5, 15 * 60, "Service unavailable")
+ self.retry(5, 15 * 60, _("Service unavailable"))
+
elif result[0] == 403:
if result[1] == -1: # another download is running
self.setWait(15 * 60)
else:
- self.setWait(result[1], reconnect=True)
+ self.setWait(result[1], True)
self.wait()
self.retry(5)
else:
self.invalidCaptcha()
- self.fail("Received invalid captcha 5 times")
+ self.fail(_("Received invalid captcha 5 times"))
+
def getFileInfo(self, token, fileId):
apiUrl = "https://api.oboom.com/1.0/info"
@@ -94,10 +123,11 @@ class OboomCom(Hoster):
else:
self.offline()
else:
- self.fail("Could not retrieve file info. Error code %s: %s" % (result[0], result[1]))
+ self.fail(_("Could not retrieve file info. Error code %s: %s") % (result[0], result[1]))
+
def getDownloadTicket(self):
- apiUrl = "https://api.oboom.com/1.0/dl"
+ apiUrl = "https://api.oboom.com/1/dl"
params = {"item": self.fileId, "http_errors": 0}
if self.premium:
params['token'] = self.sessionToken
@@ -109,22 +139,7 @@ class OboomCom(Hoster):
if result[0] == 200:
self.downloadDomain = result[1]
self.downloadTicket = result[2]
+ elif result[0] == 421:
+ self.retry(wait_time=result[2] + 60, reason=_("Connection limit exceeded"))
else:
- self.fail("Could not retrieve download ticket. Error code %s" % result[0])
-
- def setup(self):
- self.chunkLimit = 1
- self.multiDL = self.premium
-
- def process(self, pyfile):
- self.pyfile.url.replace(".com/#id=", ".com/#")
- self.pyfile.url.replace(".com/#/", ".com/#")
- self.getFileId(self.pyfile.url)
- self.getSessionToken()
- self.getFileInfo(self.sessionToken, self.fileId)
- self.pyfile.name = self.fileName
- self.pyfile.size = self.fileSize
- if not self.premium:
- self.solveCaptcha()
- self.getDownloadTicket()
- self.download("https://%s/1.0/dlh" % self.downloadDomain, get={"ticket": self.downloadTicket, "http_errors": 0})
+ self.fail(_("Could not retrieve download ticket. Error code: %s") % result[0])
diff --git a/module/plugins/hoster/OneFichierCom.py b/module/plugins/hoster/OneFichierCom.py
index 2a98a97dc..f0e16a101 100644
--- a/module/plugins/hoster/OneFichierCom.py
+++ b/module/plugins/hoster/OneFichierCom.py
@@ -1,87 +1,60 @@
# -*- coding: utf-8 -*-
-# Test links (random.bin):
-# http://5pnm24ltcw.1fichier.com/
-
import re
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class OneFichierCom(SimpleHoster):
- __name__ = "OneFichierCom"
- __type__ = "hoster"
- __pattern__ = r'(http://(?P<id>\w+)\.(?P<host>(1fichier|d(es)?fichiers|pjointe)\.(com|fr|net|org)|(cjoint|mesfichiers|piecejointe|oi)\.(org|net)|tenvoi\.(com|org|net)|dl4free\.com|alterupload\.com|megadl.fr))/?'
- __version__ = "0.61"
- __description__ = """1fichier.com hoster plugin"""
- __author_name__ = ("fragonib", "the-razer", "zoidberg", "imclem", "stickell", "Elrick69")
- __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "daniel_ AT gmx DOT net", "zoidberg@mujmail.cz",
- "imclem on github", "l.stickell@yahoo.it", "elrick69[AT]rocketmail[DOT]com")
+ __name__ = "OneFichierCom"
+ __type__ = "hoster"
+ __version__ = "0.75"
- FILE_NAME_PATTERN = r'">Filename :</th>\s*<td>(?P<N>[^<]+)</td>'
- FILE_SIZE_PATTERN = r'<th>Size :</th>\s*<td>(?P<S>[^<]+)</td>'
- OFFLINE_PATTERN = r'The (requested)? file (could not be found|has been deleted)'
+ __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+))?'
- FILE_URL_REPLACEMENTS = [(__pattern__, r'http://\g<id>.\g<host>/en/')]
+ __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", None),
+ ("stickell", "l.stickell@yahoo.it"),
+ ("Elrick69", "elrick69[AT]rocketmail[DOT]com"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
- WAITING_PATTERN = r'Warning ! Without premium status, you must wait between each downloads'
- NOT_PARALLEL = r'Warning ! Without premium status, you can download only one file at a time'
- WAIT_TIME = 10 * 60 # Retry time between each free download
- RETRY_TIME = 15 * 60 # Default retry time in seconds (if detected parallel download)
- def setup(self):
- self.multiDL = self.premium
- self.resumeDownload = True
+ NAME_PATTERN = r'>FileName :</td>\s*<td.*>(?P<N>.+?)<'
+ SIZE_PATTERN = r'>Size :</td>\s*<td.*>(?P<S>[\d.,]+) (?P<U>[\w^_]+)'
- def handleFree(self):
- self.html = self.load(self.pyfile.url, decode=True)
+ OFFLINE_PATTERN = r'File not found !\s*<'
- if self.WAITING_PATTERN in self.html:
- self.logInfo('You have to wait been each free download! Retrying in %d seconds.' % self.WAIT_TIME)
- self.waitAndRetry(self.WAIT_TIME)
- else: # detect parallel download
- m = re.search(self.NOT_PARALLEL, self.html)
- if m:
- self.waitAndRetry(self.RETRY_TIME)
+ COOKIES = [("1fichier.com", "LG", "en")]
- url, inputs = self.parseHtmlForm('action="http://%s' % self.file_info['id'])
- if not url:
- self.parseError("Download link not found")
+ WAIT_PATTERN = r'>You must wait (\d+) minutes'
- # Check for protection
- if "pass" in inputs:
- inputs['pass'] = self.getPassword()
- inputs['submit'] = "Download"
- self.download(url, post=inputs)
+ def setup(self):
+ self.multiDL = self.premium
+ self.resumeDownload = True
- # Check download
- self.checkDownloadedFile()
- def handlePremium(self):
- url, inputs = self.parseHtmlForm('action="http://%s' % self.file_info['id'])
+ def handleFree(self):
+ id = self.info['pattern']['ID1'] or self.info['pattern']['ID2']
+ url, inputs = self.parseHtmlForm('action="https://1fichier.com/\?%s' % id)
+
if not url:
- self.parseError("Download link not found")
+ self.fail(_("Download link not found"))
- # Check for protection
if "pass" in inputs:
inputs['pass'] = self.getPassword()
+
inputs['submit'] = "Download"
self.download(url, post=inputs)
- # Check download
- self.checkDownloadedFile()
-
- def checkDownloadedFile(self):
- check = self.checkDownload({"wait": self.WAITING_PATTERN})
- if check == "wait":
- self.waitAndRetry(int(self.lastcheck.group(1)) * 60)
-
- def waitAndRetry(self, wait_time):
- self.wait(wait_time, True)
- self.retry()
+ def handlePremium(self):
+ return self.handleFree()
getInfo = create_getInfo(OneFichierCom)
diff --git a/module/plugins/hoster/OronCom.py b/module/plugins/hoster/OronCom.py
new file mode 100644
index 000000000..7e8423ec9
--- /dev/null
+++ b/module/plugins/hoster/OronCom.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
index f030c9e87..54f869635 100644
--- a/module/plugins/hoster/OverLoadMe.py
+++ b/module/plugins/hoster/OverLoadMe.py
@@ -1,78 +1,82 @@
# -*- coding: utf-8 -*-
import re
-from urllib import unquote
+
from random import randrange
+from urllib import unquote
-from module.plugins.Hoster import Hoster
from module.common.json_layer import json_loads
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
from module.utils import parseFileSize
-class OverLoadMe(Hoster):
- __name__ = "OverLoadMe"
- __version__ = "0.01"
- __type__ = "hoster"
- __pattern__ = r'https?://.*overload\.me.*'
+class OverLoadMe(MultiHoster):
+ __name__ = "OverLoadMe"
+ __type__ = "hoster"
+ __version__ = "0.06"
+
+ __pattern__ = r'https?://.*overload\.me/.+'
+
__description__ = """Over-Load.me hoster plugin"""
- __author_name__ = "marley"
- __author_mail__ = "marley@over-load.me"
+ __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
+ if name.endswith("..."): #: incomplete filename, append random stuff
name += "%s.tmp" % randrange(100, 999)
return name
+
def setup(self):
- self.chunkLimit = 5
+ self.chunkLimit = 5
self.resumeDownload = True
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "Over-Load")
- self.fail("No Over-Load account provided")
- else:
- self.logDebug("Old URL: %s" % pyfile.url)
- 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)
+ def handlePremium(self):
+ data = self.account.getAccountData(self.user)
+
+ page = self.load("https://api.over-load.me/getdownload.php",
+ get={"auth": data['password'], "link": self.pyfile.url})
+ data = json_loads(page)
- self.logDebug("Returned Data: %s" % data)
+ self.logDebug("Returned Data: %s" % data)
- if data['err'] == 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'])
- new_url = data['downloadlink']
+ if data['error'] == 1:
+ self.logWarning(data['msg'])
+ self.tempOffline()
+ else:
+ if self.pyfile.name is not None and self.pyfile.name.endswith('.tmp') and data['filename']:
+ self.pyfile.name = data['filename']
+ self.pyfile.size = parseFileSize(data['filesize'])
+ self.link = data['downloadlink']
if self.getConfig("https"):
- new_url = new_url.replace("http://", "https://")
+ self.link = self.link.replace("http://", "https://")
else:
- new_url = new_url.replace("https://", "http://")
+ self.link = self.link.replace("https://", "http://")
- if new_url != pyfile.url:
- self.logDebug("New URL: %s" % new_url)
+ if self.link != self.pyfile.url:
+ self.logDebug("New URL: %s" % self.link)
- if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown") or pyfile.name.endswith('..'):
+ if self.pyfile.name.startswith("http") or self.pyfile.name.startswith("Unknown") or self.pyfile.name.endswith('..'):
# only use when name wasn't already set
- pyfile.name = self.getFilename(new_url)
+ self.pyfile.name = self.getFilename(self.link)
- self.download(new_url, disposition=True)
+
+ def checkFile(self):
+ super(OverLoadMe, self).checkFile()
check = self.checkDownload(
{"error": "<title>An error occured while processing your request</title>"})
if check == "error":
# usual this download can safely be retried
- self.retry(reason="An error occured while generating link.", wait_time=60)
+ self.retry(wait_time=60, reason=_("An error occured while generating link."))
+
+
+getInfo = create_getInfo(OverLoadMe)
diff --git a/module/plugins/hoster/PandaPlanet.py b/module/plugins/hoster/PandaPlanet.py
deleted file mode 100644
index aebc15dd9..000000000
--- a/module/plugins/hoster/PandaPlanet.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Test links:
-# test.bin - 214 B - http://pandapla.net/pew1cz3ot586
-# BigBuckBunny_320x180.mp4 - 61.7 Mb - http://pandapla.net/tz0rgjfyyoh7
-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-
-
-class PandaPlanet(XFileSharingPro):
- __name__ = "PandaPlanet"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?pandapla\.net/\w{12}'
- __version__ = "0.01"
- __description__ = """Pandapla.net hoster plugin"""
- __author_name__ = "t4skforce"
- __author_mail__ = "t4skforce1337[AT]gmail[DOT]com"
-
- HOSTER_NAME = "pandapla.net"
-
- FILE_SIZE_PATTERN = r'File Size:</b>\s*</td>\s*<td[^>]*>(?P<S>[^<]+)</td>\s*</tr>'
- FILE_NAME_PATTERN = r'File Name:</b>\s*</td>\s*<td[^>]*>(?P<N>[^<]+)</td>\s*</tr>'
- LINK_PATTERN = r'(http://([^/]*?%s|\d+\.\d+\.\d+\.\d+)(:\d+)?(/d/|(?:/files)?/\d+/\w+/)[^"\'<]+\/(?!video\.mp4)[^"\'<]+)' % HOSTER_NAME
-
-
-getInfo = create_getInfo(PandaPlanet)
diff --git a/module/plugins/hoster/PandaplaNet.py b/module/plugins/hoster/PandaplaNet.py
new file mode 100644
index 000000000..78a1ed177
--- /dev/null
+++ b/module/plugins/hoster/PandaplaNet.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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/PornhostCom.py b/module/plugins/hoster/PornhostCom.py
index 6b53dc623..71342f3e0 100644
--- a/module/plugins/hoster/PornhostCom.py
+++ b/module/plugins/hoster/PornhostCom.py
@@ -1,17 +1,21 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.Hoster import Hoster
class PornhostCom(Hoster):
- __name__ = "PornhostCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?pornhost\.com/([0-9]+/[0-9]+\.html|[0-9]+)'
- __version__ = "0.2"
+ __name__ = "PornhostCom"
+ __type__ = "hoster"
+ __version__ = "0.20"
+
+ __pattern__ = r'http://(?:www\.)?pornhost\.com/(\d+/\d+\.html|\d+)'
+
__description__ = """Pornhost.com hoster plugin"""
- __author_name__ = "jeix"
- __author_mail__ = "jeix@hasnomail.de"
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de")]
+
def process(self, pyfile):
self.download_html()
@@ -21,11 +25,13 @@ class PornhostCom(Hoster):
pyfile.name = self.get_file_name()
self.download(self.get_file_url())
+
# Old interface
def download_html(self):
url = self.pyfile.url
self.html = self.load(url)
+
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
@@ -34,15 +40,16 @@ class PornhostCom(Hoster):
url = re.search(r'download this file</label>.*?<a href="(.*?)"', self.html)
if url is None:
- url = re.search(r'"(http://dl[0-9]+\.pornhost\.com/files/.*?/.*?/.*?/.*?/.*?/.*?\..*?)"', self.html)
+ url = re.search(r'"(http://dl\d+\.pornhost\.com/files/.*?/.*?/.*?/.*?/.*?/.*?\..*?)"', self.html)
if url is None:
url = re.search(r'width: 894px; height: 675px">.*?<img src="(.*?)"', self.html)
if url is None:
- url = re.search(r'"http://file[0-9]+\.pornhost\.com/[0-9]+/.*?"',
+ url = re.search(r'"http://file\d+\.pornhost\.com/\d+/.*?"',
self.html) # TODO: fix this one since it doesn't match
return url.group(1).strip()
+
def get_file_name(self):
if not self.html:
self.download_html()
@@ -53,12 +60,13 @@ class PornhostCom(Hoster):
if name is None:
name = re.search(r'<title>pornhost\.com - free file hosting with a twist -(.*?)</title>', self.html)
if name is None:
- name = re.search(r'"http://file[0-9]+\.pornhost\.com/.*?/(.*?)"', self.html)
+ name = re.search(r'"http://file\d+\.pornhost\.com/.*?/(.*?)"', self.html)
name = name.group(1).strip() + ".flv"
return name
+
def file_exists(self):
""" returns True or False
"""
diff --git a/module/plugins/hoster/PornhubCom.py b/module/plugins/hoster/PornhubCom.py
index 45dc12929..1bb787f09 100644
--- a/module/plugins/hoster/PornhubCom.py
+++ b/module/plugins/hoster/PornhubCom.py
@@ -1,17 +1,21 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.Hoster import Hoster
class PornhubCom(Hoster):
- __name__ = "PornhubCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?pornhub\.com/view_video\.php\?viewkey=[\w\d]+'
- __version__ = "0.5"
+ __name__ = "PornhubCom"
+ __type__ = "hoster"
+ __version__ = "0.50"
+
+ __pattern__ = r'http://(?:www\.)?pornhub\.com/view_video\.php\?viewkey=\w+'
+
__description__ = """Pornhub.com hoster plugin"""
- __author_name__ = "jeix"
- __author_mail__ = "jeix@hasnomail.de"
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de")]
+
def process(self, pyfile):
self.download_html()
@@ -21,10 +25,12 @@ class PornhubCom(Hoster):
pyfile.name = self.get_file_name()
self.download(self.get_file_url())
+
def download_html(self):
url = self.pyfile.url
self.html = self.load(url)
+
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
@@ -40,7 +46,7 @@ class PornhubCom(Hoster):
post_data += "\x02\x00\x02\x2d\x31\x02\x00\x20"
post_data += "add299463d4410c6d1b1c418868225f7"
- content = self.req.load(url, post=str(post_data))
+ content = self.load(url, post=str(post_data))
new_content = ""
for x in content:
@@ -53,6 +59,7 @@ class PornhubCom(Hoster):
return re.search(r'flv_url.*(http.*?)##post_roll', content).group(1)
+
def get_file_name(self):
if not self.html:
self.download_html()
@@ -69,6 +76,7 @@ class PornhubCom(Hoster):
return name + '.flv'
+
def file_exists(self):
""" returns True or False
"""
diff --git a/module/plugins/hoster/PotloadCom.py b/module/plugins/hoster/PotloadCom.py
index 7b3b25c34..d6261af3a 100644
--- a/module/plugins/hoster/PotloadCom.py
+++ b/module/plugins/hoster/PotloadCom.py
@@ -1,20 +1,18 @@
# -*- coding: utf-8 -*-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-class PotloadCom(XFileSharingPro):
- __name__ = "PotloadCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?potload\.com/\w{12}'
- __version__ = "0.01"
- __description__ = """Potload.com hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+class PotloadCom(DeadHoster):
+ __name__ = "PotloadCom"
+ __type__ = "hoster"
+ __version__ = "0.02"
- HOSTER_NAME = "potload.com"
+ __pattern__ = r'http://(?:www\.)?potload\.com/\w{12}'
- FILE_INFO_PATTERN = r'<h[1-6]>(?P<N>.+) \((?P<S>\d+) (?P<U>\w+)\)</h'
+ __description__ = """Potload.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
getInfo = create_getInfo(PotloadCom)
diff --git a/module/plugins/hoster/Premium4Me.py b/module/plugins/hoster/Premium4Me.py
deleted file mode 100644
index e66e76ce1..000000000
--- a/module/plugins/hoster/Premium4Me.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from urllib import quote
-from os.path import exists
-from os import remove
-
-from module.plugins.Hoster import Hoster
-from module.utils import fs_encode
-
-
-class Premium4Me(Hoster):
- __name__ = "Premium4Me"
- __version__ = "0.08"
- __type__ = "hoster"
-
- __pattern__ = r'http://(?:www\.)?premium.to/.*'
- __description__ = """Premium.to hoster plugin"""
- __author_name__ = ("RaNaN", "zoidberg", "stickell")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz", "l.stickell@yahoo.it")
-
- def setup(self):
- self.resumeDownload = True
- self.chunkLimit = 1
-
- def process(self, pyfile):
- if not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "premium.to")
- self.fail("No premium.to account provided")
-
- self.logDebug("premium.to: Old URL: %s" % pyfile.url)
-
- tra = self.getTraffic()
-
- #raise timeout to 2min
- self.req.setOption("timeout", 120)
-
- self.download(
- "http://premium.to/api/getfile.php?authcode=%s&link=%s" % (self.account.authcode, quote(pyfile.url, "")),
- disposition=True)
-
- check = self.checkDownload({"nopremium": "No premium account available"})
-
- if check == "nopremium":
- self.retry(60, 5 * 60, "No premium account available")
-
- err = ''
- if self.req.http.code == '420':
- # Custom error code send - fail
- lastDownload = fs_encode(self.lastDownload)
-
- if exists(lastDownload):
- f = open(lastDownload, "rb")
- err = f.read(256).strip()
- f.close()
- remove(lastDownload)
- else:
- err = 'File does not exist'
-
- trb = self.getTraffic()
- self.logInfo("Filesize: %d, Traffic used %d, traffic left %d" % (pyfile.size, tra - trb, trb))
-
- if err:
- self.fail(err)
-
- def getTraffic(self):
- try:
- traffic = int(self.load("http://premium.to/api/traffic.php?authcode=%s" % self.account.authcode))
- except:
- traffic = 0
- return traffic
diff --git a/module/plugins/hoster/PremiumTo.py b/module/plugins/hoster/PremiumTo.py
new file mode 100644
index 000000000..fa4caad5a
--- /dev/null
+++ b/module/plugins/hoster/PremiumTo.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import with_statement
+
+from os import remove
+from os.path import exists
+from urllib import quote
+
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
+from module.utils import fs_encode
+
+
+class PremiumTo(MultiHoster):
+ __name__ = "PremiumTo"
+ __type__ = "hoster"
+ __version__ = "0.16"
+
+ __pattern__ = r'https?://(?:www\.)?premium\.to/.+'
+
+ __description__ = """Premium.to hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
+
+ def setup(self):
+ self.resumeDownload = True
+ self.chunkLimit = 1
+
+
+ def handlePremium(self):
+ #raise timeout to 2min
+ self.req.setOption("timeout", 120)
+
+ self.link = True
+ self.download("http://premium.to/api/getfile.php",
+ get={'username': self.account.username,
+ 'password': self.account.password,
+ 'link' : quote(self.pyfile.url, "")},
+ disposition=True)
+
+
+ def checkFile(self):
+ super(PremiumTo, self).checkFile()
+
+ check = self.checkDownload({"nopremium": "No premium account available"})
+
+ if check == "nopremium":
+ self.retry(60, 5 * 60, "No premium account available")
+
+ err = ''
+ if self.req.http.code == '420':
+ # Custom error code send - fail
+ lastDownload = fs_encode(self.lastDownload)
+ with open(lastDownload, "rb") as f:
+ err = f.read(256).strip()
+ remove(lastDownload)
+
+ if err:
+ self.fail(err)
+
+
+getInfo = create_getInfo(PremiumTo)
diff --git a/module/plugins/hoster/PremiumizeMe.py b/module/plugins/hoster/PremiumizeMe.py
index 7e646fdf9..07536062f 100644
--- a/module/plugins/hoster/PremiumizeMe.py
+++ b/module/plugins/hoster/PremiumizeMe.py
@@ -1,57 +1,60 @@
# -*- coding: utf-8 -*-
-from module.plugins.Hoster import Hoster
-
from module.common.json_layer import json_loads
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
-class PremiumizeMe(Hoster):
- __name__ = "PremiumizeMe"
- __version__ = "0.12"
- __type__ = "hoster"
- __description__ = """Premiumize.me hoster plugin"""
+class PremiumizeMe(MultiHoster):
+ __name__ = "PremiumizeMe"
+ __type__ = "hoster"
+ __version__ = "0.15"
- # Since we want to allow the user to specify the list of hoster to use we let MultiHoster.coreReady
- # create the regex patterns for us using getHosters in our PremiumizeMe hook.
- __pattern__ = None
+ __pattern__ = r'^unmatchable$' #: Since we want to allow the user to specify the list of hoster to use we let MultiHoster.coreReady
- __author_name__ = "Florian Franzen"
- __author_mail__ = "FlorianFranzen@gmail.com"
+ __description__ = """Premiumize.me hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Florian Franzen", "FlorianFranzen@gmail.com")]
- def process(self, pyfile):
- # Check account
- if not self.account or not self.account.canUse():
- self.logError(_("Please enter your %s account or deactivate this plugin") % "premiumize.me")
- self.fail("No valid premiumize.me account provided")
+ def handlePremium(self):
# 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
+ self.pyfile.name = self.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('.')
+ temp = self.pyfile.name.split('.')
if temp.pop() in suffix_to_remove:
- pyfile.name = ".".join(temp)
+ self.pyfile.name = ".".join(temp)
# Get account data
- (user, data) = self.account.selectAccount()
+ user, data = self.account.selectAccount()
# Get rewritten link using the premiumize.me api v1 (see https://secure.premiumize.me/?show=api)
- answer = self.load(
- "https://api.premiumize.me/pm-api/v1.php?method=directdownloadlink&params[login]=%s&params[pass]=%s&params[link]=%s" % (
- user, data['password'], pyfile.url))
- data = json_loads(answer)
+ 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]' : self.pyfile.url}))
# Check status and decide what to do
status = data['status']
+
if status == 200:
- self.download(data['result']['location'], disposition=True)
+ self.link = data['result']['location']
+ return
+
elif status == 400:
- self.fail("Invalid link")
+ 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
index ce3f3e0e0..af38c4e15 100644
--- a/module/plugins/hoster/PromptfileCom.py
+++ b/module/plugins/hoster/PromptfileCom.py
@@ -1,18 +1,4 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
@@ -20,37 +6,40 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class PromptfileCom(SimpleHoster):
- __name__ = "PromptfileCom"
- __type__ = "hoster"
+ __name__ = "PromptfileCom"
+ __type__ = "hoster"
+ __version__ = "0.12"
+
__pattern__ = r'https?://(?:www\.)?promptfile\.com/'
- __version__ = "0.1"
+
__description__ = """Promptfile.com hoster plugin"""
- __author_name__ = "igel"
- __author_mail__ = "igelkun@myopera.com"
+ __license__ = "GPLv3"
+ __authors__ = [("igel", "igelkun@myopera.com")]
+
- FILE_INFO_PATTERN = r'<span style="[^"]*" title="[^"]*">(?P<N>.*?) \((?P<S>[\d.]+) (?P<U>\w+)\)</span>'
+ 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_PATTERN = r"clip: {\s*url: '(https?://(?:www\.)promptfile[^']*)',"
+ LINK_PATTERN = r'<a href=\"(.+)\" target=\"_blank\" class=\"view_dl_link\">Download File</a>'
+
def handleFree(self):
# STAGE 1: get link to continue
m = re.search(self.CHASH_PATTERN, self.html)
if m is None:
- self.parseError("Unable to detect chash")
+ self.error(_("CHASH_PATTERN not found"))
chash = m.group(1)
- self.logDebug("read chash %s" % chash)
+ self.logDebug("Read chash %s" % chash)
# continue to stage2
self.html = self.load(self.pyfile.url, decode=True, post={'chash': chash})
# STAGE 2: get the direct link
- m = re.search(self.LINK_PATTERN, self.html, re.MULTILINE | re.DOTALL)
+ m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.parseError("Unable to detect direct link")
- direct = m.group(1)
- self.logDebug("found direct link: " + direct)
- self.download(direct, disposition=True)
+ self.error(_("LINK_PATTERN not found"))
+
+ self.download(m.group(1), disposition=True)
getInfo = create_getInfo(PromptfileCom)
diff --git a/module/plugins/hoster/PrzeklejPl.py b/module/plugins/hoster/PrzeklejPl.py
new file mode 100644
index 000000000..3a59a2c9e
--- /dev/null
+++ b/module/plugins/hoster/PrzeklejPl.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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/QuickshareCz.py b/module/plugins/hoster/QuickshareCz.py
index f56daa1af..85c25f6f0 100644
--- a/module/plugins/hoster/QuickshareCz.py
+++ b/module/plugins/hoster/QuickshareCz.py
@@ -1,45 +1,35 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from pycurl import FOLLOWLOCATION
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class QuickshareCz(SimpleHoster):
- __name__ = "QuickshareCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:[^/]*\.)?quickshare.cz/stahnout-soubor/.*'
- __version__ = "0.54"
+ __name__ = "QuickshareCz"
+ __type__ = "hoster"
+ __version__ = "0.55"
+
+ __pattern__ = r'http://(?:[^/]*\.)?quickshare\.cz/stahnout-soubor/.+'
+
__description__ = """Quickshare.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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>'
- FILE_NAME_PATTERN = r'<th width="145px">Název:</th>\s*<td style="word-wrap:break-word;">(?P<N>[^<]+)</td>'
- FILE_SIZE_PATTERN = r'<th>Velikost:</th>\s*<td>(?P<S>[0-9.]+) (?P<U>[kKMG])i?B</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+) = ([0-9.]+|'[^']*')", self.html))
+ 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']
@@ -47,11 +37,11 @@ class QuickshareCz(SimpleHoster):
if self.premium:
if 'UU_prihlasen' in self.jsvars:
if self.jsvars['UU_prihlasen'] == '0':
- self.logWarning('User not logged in')
+ 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.logWarning(_("Not enough credit left"))
self.premium = False
if self.premium:
@@ -61,7 +51,8 @@ class QuickshareCz(SimpleHoster):
check = self.checkDownload({"err": re.compile(r"\AChyba!")}, max_size=100)
if check == "err":
- self.fail("File not m or plugin defect")
+ self.fail(_("File not m or plugin defect"))
+
def handleFree(self):
# get download url
@@ -74,10 +65,10 @@ class QuickshareCz(SimpleHoster):
self.header = self.req.http.header
self.req.http.c.setopt(FOLLOWLOCATION, 1)
- m = re.search("Location\s*:\s*(.*)", self.header, re.I)
+ 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.fail(_("File not found"))
+ download_url = m.group(1).rstrip() #@TODO: Remove .rstrip() in 0.4.10
self.logDebug("FREE URL2:" + download_url)
# check errors
@@ -88,15 +79,15 @@ class QuickshareCz(SimpleHoster):
elif m.group(1) == '2':
self.retry(60, 60, "No free slots available")
else:
- self.fail('Error %d' % m.group(1))
+ self.fail(_("Error %d") % m.group(1))
# download file
self.download(download_url)
+
def handlePremium(self):
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.logDebug("PREMIUM URL:" + download_url, data)
self.download(download_url, get=data)
diff --git a/module/plugins/hoster/RPNetBiz.py b/module/plugins/hoster/RPNetBiz.py
index 7c6892d8d..bffa5ef85 100644
--- a/module/plugins/hoster/RPNetBiz.py
+++ b/module/plugins/hoster/RPNetBiz.py
@@ -2,76 +2,81 @@
import re
-from module.plugins.Hoster import Hoster
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
from module.common.json_layer import json_loads
-class RPNetBiz(Hoster):
- __name__ = "RPNetBiz"
- __version__ = "0.1"
- __type__ = "hoster"
+class RPNetBiz(MultiHoster):
+ __name__ = "RPNetBiz"
+ __type__ = "hoster"
+ __version__ = "0.13"
+
__description__ = """RPNet.biz hoster plugin"""
- __pattern__ = r'https?://.*rpnet\.biz'
- __author_name__ = "Dman"
- __author_mail__ = "dmanugm@gmail.com"
+ __license__ = "GPLv3"
+
+ __pattern__ = r'https?://.+rpnet\.biz'
+ __authors__ = [("Dman", "dmanugm@gmail.com")]
+
def setup(self):
- self.chunkLimit = -1
+ self.chunkLimit = -1
self.resumeDownload = True
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- link_status = {'generated': pyfile.url}
- elif not self.account:
- # Check account
- self.logError(_("Please enter your %s account or deactivate this plugin") % "rpnet")
- self.fail("No rpnet account provided")
- else:
- (user, data) = self.account.selectAccount()
- self.logDebug("Original URL: %s" % pyfile.url)
- # Get the download link
- response = self.load("https://premium.rpnet.biz/client_api.php",
- get={"username": user, "password": data['password'],
- "action": "generate", "links": pyfile.url})
+ def handlePremium(self):
+ user, data = self.account.selectAccount()
+
+ self.logDebug("Original URL: %s" % self.pyfile.url)
+ # Get the download link
+ res = self.load("https://premium.rpnet.biz/client_api.php",
+ get={"username": user,
+ "password": data['password'],
+ "action": "generate",
+ "links": self.pyfile.url})
- self.logDebug("JSON data: %s" % response)
- link_status = json_loads(response)['links'][0] # get the first link... since we only queried one
+ 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
+ # 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()
- # 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))
- response = 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" % response)
- download_status = json_loads(response)['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")
+ 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.download(link_status['generated'], disposition=True)
+ 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")
+ 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
new file mode 100644
index 000000000..9fd20e69e
--- /dev/null
+++ b/module/plugins/hoster/RapideoPl.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+
+from module.common.json_layer import json_loads as loads
+from module.plugins.internal.SimpleHoster import SimpleHoster
+
+
+class RapideoPl(SimpleHoster):
+ __name__ = "RapideoPl"
+ __version__ = "0.01"
+ __type__ = "hoster"
+ __description__ = "Rapideo.pl 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"
+ }
+
+ _usr = False
+ _pwd = False
+
+ def setup(self):
+ self.resumeDownload = True
+ self.multiDL = True
+
+ def get_username_password(self):
+ if not self.account:
+ self.fail(_("Please enter your %s account or deactivate this plugin") % "Rapideo.pl")
+ else:
+ self._usr = self.account.getAccountData(self.user).get('usr')
+ self._pwd = self.account.getAccountData(self.user).get('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 process(self, pyfile):
+ self.get_username_password()
+ try:
+ data = self.runFileQuery(pyfile.url, 'fileinfo')
+ except Exception:
+ self.logDebug("RunFileQuery error")
+ self.tempOffline()
+
+ try:
+ parsed = 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 webiste \
+ directly. Update this plugin." % parsed["hosting"])
+
+ pyfile.name = parsed["filename"]
+ pyfile.size = parsed["filesize"]
+
+ try:
+ result_dl = self.runFileQuery(pyfile.url, 'filedownload')
+ except Exception:
+ self.logDebug("runFileQuery error #2")
+ self.tempOffline()
+
+ self.download(result_dl, disposition=True)
diff --git a/module/plugins/hoster/RapidfileshareNet.py b/module/plugins/hoster/RapidfileshareNet.py
new file mode 100644
index 000000000..14d62ee74
--- /dev/null
+++ b/module/plugins/hoster/RapidfileshareNet.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+
+class RapidfileshareNet(XFSHoster):
+ __name__ = "RapidfileshareNet"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?rapidfileshare\.net/\w{12}'
+
+ __description__ = """Rapidfileshare.net hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("guidobelix", "guidobelix@hotmail.it")]
+
+
+ HOSTER_DOMAIN = "rapidfileshare.net"
+
+ 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.<'
+
+
+ def handlePremium(self):
+ self.fail(_("Premium download not implemented"))
+
+
+getInfo = create_getInfo(RapidfileshareNet)
diff --git a/module/plugins/hoster/RapidgatorNet.py b/module/plugins/hoster/RapidgatorNet.py
index 17ded3297..ba6cfcd5c 100644
--- a/module/plugins/hoster/RapidgatorNet.py
+++ b/module/plugins/hoster/RapidgatorNet.py
@@ -1,18 +1,4 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
import re
@@ -20,75 +6,84 @@ from pycurl import HTTPHEADER
from module.common.json_layer import json_loads
from module.network.HTTPRequest import BadHeader
-
-from module.plugins.hoster.UnrestrictLi import secondsToMidnight
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-from module.plugins.internal.CaptchaService import ReCaptcha, SolveMedia, AdsCaptcha
+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"
+ __name__ = "RapidgatorNet"
+ __type__ = "hoster"
+ __version__ = "0.27"
+
__pattern__ = r'http://(?:www\.)?(rapidgator\.net|rg\.to)/file/\w+'
- __version__ = "0.22"
+
__description__ = """Rapidgator.net hoster plugin"""
- __author_name__ = ("zoidberg", "chrox", "stickell", "Walter Purcaro")
- __author_mail__ = ("zoidberg@mujmail.cz", "", "l.stickell@yahoo.it", "vuolter@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("chrox", None),
+ ("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
API_URL = "http://rapidgator.net/api/file"
- FILE_NAME_PATTERN = r'<title>Download file (?P<N>.*)</title>'
- FILE_SIZE_PATTERN = r'File size:\s*<strong>(?P<S>[\d\.]+) (?P<U>\w+)</strong>'
+ 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*'?(.*?)'?;"
+ JSVARS_PATTERN = r'\s+var\s*(startTimerUrl|getDownloadUrl|captchaUrl|fid|secs)\s*=\s*\'?(.*?)\'?;'
PREMIUM_ONLY_ERROR_PATTERN = r'You can download files up to|This file can be downloaded by premium only<'
DOWNLOAD_LIMIT_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)\s*(\d+)\s*(hour|min)'
- LINK_PATTERN = r"return '(http://\w+.rapidgator.net/.*)';"
+ LINK_PATTERN = r'return \'(http://\w+.rapidgator.net/.*)\';'
- RECAPTCHA_KEY_PATTERN = r'"http://api\.recaptcha\.net/challenge\?k=(.*?)"'
- ADSCAPTCHA_SRC_PATTERN = r'(http://api\.adscaptcha\.com/Get\.aspx[^"\']*)'
+ 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):
- self.resumeDownload = self.multiDL = self.premium
- self.sid = None
- self.chunkLimit = 1
- self.req.setOption("timeout", 120)
- def process(self, pyfile):
+ def setup(self):
if self.account:
self.sid = self.account.getAccountData(self.user).get('SID', None)
+ else:
+ self.sid = None
if self.sid:
- self.handlePremium()
- else:
- self.handleFree()
+ 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)
+ 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)
+ 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):
#self.logDebug("ACCOUNT_DATA", self.account.getAccountData(self.user))
self.api_data = self.api_response('info')
@@ -98,9 +93,8 @@ class RapidgatorNet(SimpleHoster):
url = self.api_response('download')['url']
self.download(url)
- def handleFree(self):
- self.html = self.load(self.pyfile.url, decode=True)
+ def handleFree(self):
self.checkFree()
jsvars = dict(re.findall(self.JSVARS_PATTERN, self.html))
@@ -113,7 +107,7 @@ class RapidgatorNet(SimpleHoster):
jsvars.get('startTimerUrl', '/download/AjaxStartTimer'), jsvars['fid'])
jsvars.update(self.getJsonResponse(url))
- self.wait(int(jsvars.get('secs', 45)) + 1, False)
+ self.wait(int(jsvars.get('secs', 45)), False)
url = "http://rapidgator.net%s?sid=%s" % (
jsvars.get('getDownloadUrl', '/download/AjaxGetDownload'), jsvars['sid'])
@@ -125,7 +119,7 @@ class RapidgatorNet(SimpleHoster):
url = "http://rapidgator.net%s" % jsvars.get('captchaUrl', '/download/captcha')
self.html = self.load(url)
- for _ in xrange(5):
+ for _i in xrange(5):
m = re.search(self.LINK_PATTERN, self.html)
if m:
link = m.group(1)
@@ -134,28 +128,27 @@ class RapidgatorNet(SimpleHoster):
break
else:
captcha, captcha_key = self.getCaptcha()
- captcha_challenge, captcha_response = captcha.challenge(captcha_key)
+ challenge, response = captcha.challenge(captcha_key)
- self.html = self.load(url, post={
- "DownloadCaptchaForm[captcha]": "",
- "adcopy_challenge": captcha_challenge,
- "adcopy_response": captcha_response
- })
+ 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.parseError("Download link")
+ self.error(_("Download link"))
+
def getCaptcha(self):
- m = re.search(self.ADSCAPTCHA_SRC_PATTERN, self.html)
+ m = re.search(self.ADSCAPTCHA_PATTERN, self.html)
if m:
captcha_key = m.group(1)
captcha = AdsCaptcha(self)
else:
- m = re.search(self.RECAPTCHA_KEY_PATTERN, self.html)
+ m = re.search(self.RECAPTCHA_PATTERN, self.html)
if m:
captcha_key = m.group(1)
captcha = ReCaptcha(self)
@@ -165,14 +158,15 @@ class RapidgatorNet(SimpleHoster):
captcha_key = m.group(1)
captcha = SolveMedia(self)
else:
- self.parseError("Captcha")
+ self.error(_("Captcha"))
return captcha, captcha_key
+
def checkFree(self):
m = re.search(self.PREMIUM_ONLY_ERROR_PATTERN, self.html)
if m:
- self.fail("Premium account needed for download")
+ self.fail(_("Premium account needed for download"))
else:
m = re.search(self.WAIT_PATTERN, self.html)
@@ -183,7 +177,7 @@ class RapidgatorNet(SimpleHoster):
if m is None:
return
elif m.group(1) == "daily":
- self.logWarning("You have reached your daily downloads limit for today")
+ self.logWarning(_("You have reached your daily downloads limit for today"))
wait_time = secondsToMidnight(gmt=2)
else:
wait_time = 1 * 60 * 60
@@ -192,12 +186,13 @@ class RapidgatorNet(SimpleHoster):
self.wait(wait_time, True)
self.retry()
+
def getJsonResponse(self, url):
- response = self.load(url, decode=True)
- if not response.startswith('{'):
+ res = self.load(url, decode=True)
+ if not res.startswith('{'):
self.retry()
- self.logDebug(url, response)
- return json_loads(response)
+ self.logDebug(url, res)
+ return json_loads(res)
getInfo = create_getInfo(RapidgatorNet)
diff --git a/module/plugins/hoster/RapidshareCom.py b/module/plugins/hoster/RapidshareCom.py
deleted file mode 100644
index b50f1c568..000000000
--- a/module/plugins/hoster/RapidshareCom.py
+++ /dev/null
@@ -1,227 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# v1.36
-# * fixed call checkfiles subroutine
-# v1.35
-# * fixed rs-urls in handleFree(..) and freeWait(..)
-# * removed getInfo(..) function as it was not used anywhere (in this file)
-# * removed some (old?) comment blocks
-
-import re
-
-from module.network.RequestFactory import getURL
-from module.plugins.Hoster import Hoster
-
-
-def getInfo(urls):
- ids = ""
- names = ""
-
- p = re.compile(RapidshareCom.__pattern__)
-
- for url in urls:
- r = p.search(url)
- if r.group("name"):
- ids += "," + r.group("id")
- names += "," + r.group("name")
- elif r.group("name_new"):
- ids += "," + r.group("id_new")
- names += "," + r.group("name_new")
-
- url = "http://api.rapidshare.com/cgi-bin/rsapi.cgi?sub=checkfiles&files=%s&filenames=%s" % (ids[1:], names[1:])
-
- api = getURL(url)
- result = []
- i = 0
- for res in api.split():
- tmp = res.split(",")
- if tmp[4] in ("0", "4", "5"):
- status = 1
- elif tmp[4] == "1":
- status = 2
- else:
- status = 3
-
- result.append((tmp[1], tmp[2], status, urls[i]))
- i += 1
-
- yield result
-
-
-class RapidshareCom(Hoster):
- __name__ = "RapidshareCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?rapidshare.com/(?:files/(?P<id>\d*?)/(?P<name>[^?]+)|#!download\|(?:\w+)\|(?P<id_new>\d+)\|(?P<name_new>[^|]+))'
- __version__ = "1.39"
- __description__ = """Rapidshare.com hoster plugin"""
- __config__ = [("server",
- "Cogent;Deutsche Telekom;Level(3);Level(3) #2;GlobalCrossing;Level(3) #3;Teleglobe;GlobalCrossing #2;TeliaSonera #2;Teleglobe #2;TeliaSonera #3;TeliaSonera",
- "Preferred Server", "None")]
- __author_name__ = ("spoob", "RaNaN", "mkaay")
- __author_mail__ = ("spoob@pyload.org", "ranan@pyload.org", "mkaay@mkaay.de")
-
- def setup(self):
- self.no_download = True
- self.api_data = None
- self.offset = 0
- self.dl_dict = {}
-
- self.id = None
- self.name = None
-
- self.chunkLimit = -1 if self.premium else 1
- self.multiDL = self.resumeDownload = self.premium
-
- def process(self, pyfile):
- self.url = pyfile.url
- self.prepare()
-
- def prepare(self):
- m = re.match(self.__pattern__, self.url)
-
- if m.group("name"):
- self.id = m.group("id")
- self.name = m.group("name")
- else:
- self.id = m.group("id_new")
- self.name = m.group("name_new")
-
- self.download_api_data()
- if self.api_data['status'] == "1":
- self.pyfile.name = self.get_file_name()
-
- if self.premium:
- self.handlePremium()
- else:
- self.handleFree()
-
- elif self.api_data['status'] == "2":
- self.logInfo(_("Rapidshare: Traffic Share (direct download)"))
- self.pyfile.name = self.get_file_name()
-
- self.download(self.pyfile.url, get={"directstart": 1})
-
- elif self.api_data['status'] in ("0", "4", "5"):
- self.offline()
- elif self.api_data['status'] == "3":
- self.tempOffline()
- else:
- self.fail("Unknown response code.")
-
- def handleFree(self):
- while self.no_download:
- self.dl_dict = self.freeWait()
-
- #tmp = "#!download|%(server)s|%(id)s|%(name)s|%(size)s"
- download = "http://%(host)s/cgi-bin/rsapi.cgi?sub=download&editparentlocation=0&bin=1&fileid=%(id)s&filename=%(name)s&dlauth=%(auth)s" % self.dl_dict
-
- self.logDebug("RS API Request: %s" % download)
- self.download(download, ref=False)
-
- check = self.checkDownload({"ip": "You need RapidPro to download more files from your IP address",
- "auth": "Download auth invalid"})
- if check == "ip":
- self.setWait(60)
- self.logInfo(_("Already downloading from this ip address, waiting 60 seconds"))
- self.wait()
- self.handleFree()
- elif check == "auth":
- self.logInfo(_("Invalid Auth Code, download will be restarted"))
- self.offset += 5
- self.handleFree()
-
- def handlePremium(self):
- info = self.account.getAccountInfo(self.user, True)
- self.logDebug("%s: Use Premium Account" % self.__name__)
- url = self.api_data['mirror']
- self.download(url, get={"directstart": 1})
-
- def download_api_data(self, force=False):
- """
- http://images.rapidshare.com/apidoc.txt
- """
- if self.api_data and not force:
- return
- api_url_base = "http://api.rapidshare.com/cgi-bin/rsapi.cgi"
- api_param_file = {"sub": "checkfiles", "incmd5": "1", "files": self.id, "filenames": self.name}
- src = self.load(api_url_base, cookies=False, get=api_param_file).strip()
- self.logDebug("RS INFO API: %s" % src)
- if src.startswith("ERROR"):
- return
- fields = src.split(",")
-
- # status codes:
- # 0=File not found
- # 1=File OK (Anonymous downloading)
- # 3=Server down
- # 4=File marked as illegal
- # 5=Anonymous file locked, because it has more than 10 downloads already
- # 50+n=File OK (TrafficShare direct download type "n" without any logging.)
- # 100+n=File OK (TrafficShare direct download type "n" with logging.
- # Read our privacy policy to see what is logged.)
-
- self.api_data = {"fileid": fields[0], "filename": fields[1], "size": int(fields[2]), "serverid": fields[3],
- "status": fields[4], "shorthost": fields[5], "checksum": fields[6].strip().lower()}
-
- if int(self.api_data['status']) > 100:
- self.api_data['status'] = str(int(self.api_data['status']) - 100)
- elif int(self.api_data['status']) > 50:
- self.api_data['status'] = str(int(self.api_data['status']) - 50)
-
- self.api_data['mirror'] = "http://rs%(serverid)s%(shorthost)s.rapidshare.com/files/%(fileid)s/%(filename)s" % self.api_data
-
- def freeWait(self):
- """downloads html with the important information
- """
- self.no_download = True
-
- id = self.id
- name = self.name
-
- prepare = "https://api.rapidshare.com/cgi-bin/rsapi.cgi?sub=download&fileid=%(id)s&filename=%(name)s&try=1&cbf=RSAPIDispatcher&cbid=1" % {
- "name": name, "id": id}
-
- self.logDebug("RS API Request: %s" % prepare)
- result = self.load(prepare, ref=False)
- self.logDebug("RS API Result: %s" % result)
-
- between_wait = re.search("You need to wait (\d+) seconds", result)
-
- if "You need RapidPro to download more files from your IP address" in result:
- self.setWait(60)
- self.logInfo(_("Already downloading from this ip address, waiting 60 seconds"))
- self.wait()
- elif ("Too many users downloading from this server right now" in result or
- "All free download slots are full" in result):
- self.setWait(120)
- self.logInfo(_("RapidShareCom: No free slots"))
- self.wait()
- elif "This file is too big to download it for free" in result:
- self.fail(_("You need a premium account for this file"))
- elif "Filename invalid." in result:
- self.fail(_("Filename reported invalid"))
- elif between_wait:
- self.setWait(int(between_wait.group(1)))
- self.wantReconnect = True
- self.wait()
- else:
- self.no_download = False
-
- tmp, info = result.split(":")
- data = info.split(",")
-
- dl_dict = {"id": id,
- "name": name,
- "host": data[0],
- "auth": data[1],
- "server": self.api_data['serverid'],
- "size": self.api_data['size']}
- self.setWait(int(data[2]) + 2 + self.offset)
- self.wait()
-
- return dl_dict
-
- def get_file_name(self):
- if self.api_data['filename']:
- return self.api_data['filename']
- return self.url.split("/")[-1]
diff --git a/module/plugins/hoster/RapiduNet.py b/module/plugins/hoster/RapiduNet.py
new file mode 100644
index 000000000..a3b2cffcd
--- /dev/null
+++ b/module/plugins/hoster/RapiduNet.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from pycurl import HTTPHEADER
+from time import time, altzone
+
+from module.common.json_layer import json_loads
+from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class RapiduNet(SimpleHoster):
+ __name__ = "RapiduNet"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
+ __pattern__ = r'https?://(?:www\.)?rapidu\.net/(?P<ID>\d{10})'
+
+ __description__ = """Rapidu.net hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("prOq", None)]
+
+
+ COOKIES = [("rapidu.net", "rapidu_lang", "en")]
+
+ FILE_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 = True
+ self.limitDL = 0 if self.premium else 2
+
+
+ def handleFree(self):
+ self.req.http.lastURL = self.pyfile.url
+ self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"])
+
+ jsvars = self.getJsonResponse("https://rapidu.net/ajax.php?a=getLoadTimeToDownload", {'_go': None})
+
+ 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):
+ challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
+
+ jsvars = self.getJsonResponse("https://rapidu.net/ajax.php?a=getCheckCaptcha",
+ {'_go' : None,
+ 'captcha1': challenge,
+ 'captcha2': response,
+ 'fileId' : self.info['ID']})
+ if jsvars['message'] == 'success':
+ self.download(jsvars['url'])
+ break
+
+
+ def getJsonResponse(self, url, post_data):
+ res = self.load(url, post=post_data, decode=True)
+ if not res.startswith('{'):
+ self.retry()
+
+ self.logDebug(url, res)
+
+ return json_loads(res)
+
+
+getInfo = create_getInfo(RapiduNet)
diff --git a/module/plugins/hoster/RarefileNet.py b/module/plugins/hoster/RarefileNet.py
index 7dd4164f6..2be952efe 100644
--- a/module/plugins/hoster/RarefileNet.py
+++ b/module/plugins/hoster/RarefileNet.py
@@ -2,35 +2,24 @@
import re
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-from module.utils import html_unescape
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class RarefileNet(XFileSharingPro):
- __name__ = "RarefileNet"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?rarefile.net/\w{12}'
- __version__ = "0.03"
- __description__ = """Rarefile.net hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+class RarefileNet(XFSHoster):
+ __name__ = "RarefileNet"
+ __type__ = "hoster"
+ __version__ = "0.09"
+
+ __pattern__ = r'http://(?:www\.)?rarefile\.net/\w{12}'
- HOSTER_NAME = "rarefile.net"
+ __description__ = """Rarefile.net hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<td><font color="red">(?P<N>.*?)</font></td>'
- FILE_SIZE_PATTERN = r'<td>Size : (?P<S>.+?)&nbsp;'
- LINK_PATTERN = r'<a href="(?P<link>[^"]+)">(?P=link)</a>'
- def setup(self):
- self.resumeDownload = self.multiDL = self.premium
+ HOSTER_DOMAIN = "rarefile.net"
- def handleCaptcha(self, inputs):
- captcha_div = re.search(r'<b>Enter code.*?<div.*?>(.*?)</div>', self.html, re.S).group(1)
- self.logDebug(captcha_div)
- numerals = re.findall('<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>', html_unescape(captcha_div))
- inputs['code'] = "".join([a[1] for a in sorted(numerals, key=lambda num: int(num[0]))])
- self.logDebug("CAPTCHA", inputs['code'], numerals)
- return 3
+ 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
index 17cd86ccd..e8bb44ee5 100644
--- a/module/plugins/hoster/RealdebridCom.py
+++ b/module/plugins/hoster/RealdebridCom.py
@@ -1,88 +1,86 @@
# -*- coding: utf-8 -*-
import re
-from time import time
-from urllib import quote, unquote
+
from random import randrange
+from urllib import quote, unquote
+from time import time
-from module.utils import parseFileSize
from module.common.json_layer import json_loads
-from module.plugins.Hoster import Hoster
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
+from module.utils import parseFileSize
+
+class RealdebridCom(MultiHoster):
+ __name__ = "RealdebridCom"
+ __type__ = "hoster"
+ __version__ = "0.60"
-class RealdebridCom(Hoster):
- __name__ = "RealdebridCom"
- __version__ = "0.53"
- __type__ = "hoster"
+ __pattern__ = r'https?://s\d+\.real-debrid\.com/dl/[\w^_]+'
- __pattern__ = r'https?://(?:[^/]*\.)?real-debrid\..*'
__description__ = """Real-Debrid.com hoster plugin"""
- __author_name__ = "Devirex Hazzard"
- __author_mail__ = "naibaf_11@yahoo.de"
+ __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
+ 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
+ self.chunkLimit = 3
self.resumeDownload = True
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "Real-debrid")
- self.fail("No Real-debrid account provided")
- else:
- self.logDebug("Old URL: %s" % pyfile.url)
- password = self.getPassword().splitlines()
- if not password:
- password = ""
- else:
- password = password[0]
- url = "https://real-debrid.com/ajax/unrestrict.php?lang=en&link=%s&password=%s&time=%s" % (
- quote(pyfile.url, ""), password, int(time() * 1000))
- page = self.load(url)
- data = json_loads(page)
+ def handlePremium(self):
+ data = json_loads(self.load("https://real-debrid.com/ajax/unrestrict.php",
+ get={'lang' : "en",
+ 'link' : self.pyfile.url,
+ 'password': self.getPassword(),
+ 'time' : int(time() * 1000)}))
- self.logDebug("Returned Data: %s" % data)
+ 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()
+ if data['error'] != 0:
+ if data['message'] == "Your file is unavailable on the hoster.":
+ self.offline()
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'])
- new_url = data['generated_links'][0][-1]
+ self.logWarning(data['message'])
+ self.tempOffline()
+ else:
+ if self.pyfile.name is not None and self.pyfile.name.endswith('.tmp') and data['file_name']:
+ self.pyfile.name = data['file_name']
+ self.pyfile.size = parseFileSize(data['file_size'])
+ self.link = data['generated_links'][0][-1]
if self.getConfig("https"):
- new_url = new_url.replace("http://", "https://")
+ self.link = self.link.replace("http://", "https://")
else:
- new_url = new_url.replace("https://", "http://")
+ self.link = self.link.replace("https://", "http://")
- if new_url != pyfile.url:
- self.logDebug("New URL: %s" % new_url)
+ if self.link != self.pyfile.url:
+ self.logDebug("New URL: %s" % self.link)
- if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown") or pyfile.name.endswith('..'):
+ if self.pyfile.name.startswith("http") or self.pyfile.name.startswith("Unknown") or self.pyfile.name.endswith('..'):
#only use when name wasnt already set
- pyfile.name = self.getFilename(new_url)
+ self.pyfile.name = self.getFilename(self.link)
+
- self.download(new_url, disposition=True)
+ def checkFile(self):
+ super(RealdebridCom, self).checkFile()
check = self.checkDownload(
{"error": "<title>An error occured while processing your request</title>"})
if check == "error":
#usual this download can safely be retried
- self.retry(wait_time=60, reason="An error occured while generating link.")
+ self.retry(wait_time=60, reason=_("An error occured while generating link"))
+
+
+getInfo = create_getInfo(RealdebridCom)
diff --git a/module/plugins/hoster/RedtubeCom.py b/module/plugins/hoster/RedtubeCom.py
index d9cb6489a..d68fbe262 100644
--- a/module/plugins/hoster/RedtubeCom.py
+++ b/module/plugins/hoster/RedtubeCom.py
@@ -1,18 +1,22 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.Hoster import Hoster
from module.unescape import unescape
class RedtubeCom(Hoster):
- __name__ = "RedtubeCom"
- __type__ = "hoster"
+ __name__ = "RedtubeCom"
+ __type__ = "hoster"
+ __version__ = "0.20"
+
__pattern__ = r'http://(?:www\.)?redtube\.com/\d+'
- __version__ = "0.2"
+
__description__ = """Redtube.com hoster plugin"""
- __author_name__ = "jeix"
- __author_mail__ = "jeix@hasnomail.de"
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de")]
+
def process(self, pyfile):
self.download_html()
@@ -22,10 +26,12 @@ class RedtubeCom(Hoster):
pyfile.name = self.get_file_name()
self.download(self.get_file_url())
+
def download_html(self):
url = self.pyfile.url
self.html = self.load(url)
+
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
@@ -36,12 +42,14 @@ class RedtubeCom(Hoster):
return file_url
+
def get_file_name(self):
if not self.html:
self.download_html()
return re.search('<title>(.*?)- RedTube - Free Porn Videos</title>', self.html).group(1).strip() + ".flv"
+
def file_exists(self):
""" returns True or False
"""
diff --git a/module/plugins/hoster/RehostTo.py b/module/plugins/hoster/RehostTo.py
index 79c06f863..2971a6781 100644
--- a/module/plugins/hoster/RehostTo.py
+++ b/module/plugins/hoster/RehostTo.py
@@ -1,37 +1,42 @@
# -*- coding: utf-8 -*-
from urllib import quote, unquote
-from module.plugins.Hoster import Hoster
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
+
+
+class RehostTo(MultiHoster):
+ __name__ = "RehostTo"
+ __type__ = "hoster"
+ __version__ = "0.16"
+
+ __pattern__ = r'https?://.*rehost\.to\..+'
-class RehostTo(Hoster):
- __name__ = "RehostTo"
- __version__ = "0.13"
- __type__ = "hoster"
- __pattern__ = r'https?://.*rehost.to\..*'
__description__ = """Rehost.com hoster plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
+
def getFilename(self, url):
return unquote(url.rsplit("/", 1)[1])
+
def setup(self):
- self.chunkLimit = 1
+ self.chunkLimit = 1
self.resumeDownload = True
- def process(self, pyfile):
- if not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "rehost.to")
- self.fail("No rehost.to account provided")
+ def handlePremium(self):
data = self.account.getAccountInfo(self.user)
long_ses = data['long_ses']
- self.logDebug("Rehost.to: Old URL: %s" % pyfile.url)
- new_url = "http://rehost.to/process_download.php?user=cookie&pass=%s&dl=%s" % (long_ses, quote(pyfile.url, ""))
-
#raise timeout to 2min
self.req.setOption("timeout", 120)
- self.download(new_url, disposition=True)
+ self.link = True
+ self.download("http://rehost.to/process_download.php",
+ get={'user': "cookie", 'pass': long_ses, 'dl': quote(self.pyfile.url, "")},
+ disposition=True)
+
+
+getInfo = create_getInfo(RehostTo)
diff --git a/module/plugins/hoster/RemixshareCom.py b/module/plugins/hoster/RemixshareCom.py
index a0f67e0b2..ed171895e 100644
--- a/module/plugins/hoster/RemixshareCom.py
+++ b/module/plugins/hoster/RemixshareCom.py
@@ -1,29 +1,32 @@
# -*- coding: utf-8 -*-
-
-# Test link:
+#
+# 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/module/network/HTTPRequest.py
-
import re
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class RemixshareCom(SimpleHoster):
- __name__ = "RemixshareCom"
- __type__ = "hoster"
+ __name__ = "RemixshareCom"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
__pattern__ = r'https?://remixshare\.com/(download|dl)/\w+'
- __version__ = "0.01"
+
__description__ = """Remixshare.com hoster plugin"""
- __author_name__ = ("zapp-brannigan", "Walter Purcaro")
- __author_mail__ = ("fuerst.reinje@web.de", "vuolter@gmail.com")
+ __license__ = "GPLv3"
+ __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
- FILE_INFO_PATTERN = r'title=\'.+?\'>(?P<N>.+?)</span><span class=\'light2\'>&nbsp;\((?P<S>\d+)&nbsp;(?P<U>\w+)\)<'
+ INFO_PATTERN = r'title=\'.+?\'>(?P<N>.+?)</span><span class=\'light2\'>&nbsp;\((?P<S>\d+)&nbsp;(?P<U>[\w^_]+)\)<'
OFFLINE_PATTERN = r'<h1>Ooops!<'
LINK_PATTERN = r'(http://remixshare\.com/downloadfinal/.+?)"'
@@ -35,23 +38,23 @@ class RemixshareCom(SimpleHoster):
self.multiDL = True
self.chunkLimit = 1
+
def handleFree(self):
b = re.search(self.LINK_PATTERN, self.html)
if not b:
- self.parseError("Cannot parse download url")
+ self.error(_("Cannot parse download url"))
c = re.search(self.TOKEN_PATTERN, self.html)
if not c:
- self.parseError("Cannot parse file token")
+ self.error(_("Cannot parse file token"))
dl_url = 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))
+ self.wait(int(seconds.group(1)))
# Finally start downloading...
- self.logDebug("Download URL = r" + dl_url)
self.download(dl_url, disposition=True)
diff --git a/module/plugins/hoster/RgHostNet.py b/module/plugins/hoster/RgHostNet.py
index 80954e67b..aa4830563 100644
--- a/module/plugins/hoster/RgHostNet.py
+++ b/module/plugins/hoster/RgHostNet.py
@@ -1,28 +1,26 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class RgHostNet(SimpleHoster):
- __name__ = "RgHostNet"
- __type__ = "hoster"
+ __name__ = "RgHostNet"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
__pattern__ = r'http://(?:www\.)?rghost\.net/\d+(?:r=\d+)?'
- __version__ = "0.01"
+
__description__ = """RgHost.net hoster plugin"""
- __author_name__ = "z00nx"
- __author_mail__ = "z00nx0@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("z00nx", "z00nx0@gmail.com")]
- FILE_INFO_PATTERN = r'<h1>\s+(<a[^>]+>)?(?P<N>[^<]+)(</a>)?\s+<small[^>]+>\s+\((?P<S>[^)]+)\)\s+</small>\s+</h1>'
+
+ 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_PATTERN = r'''<a\s+href="([^"]+)"\s+class="btn\s+large\s+download"[^>]+>Download</a>'''
-
- def handleFree(self):
- m = re.search(self.LINK_PATTERN, self.html)
- if m is None:
- self.parseError("Unable to detect the direct link")
- download_link = m.group(1)
- self.download(download_link, disposition=True)
+
+ 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/RyushareCom.py b/module/plugins/hoster/RyushareCom.py
index bc81f03c0..0964c51fc 100644
--- a/module/plugins/hoster/RyushareCom.py
+++ b/module/plugins/hoster/RyushareCom.py
@@ -1,30 +1,34 @@
# -*- coding: utf-8 -*-
-
-# Test links (random.bin):
+#
+# Test links:
# http://ryushare.com/cl0jy8ric2js/random.bin
import re
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
from module.plugins.internal.CaptchaService import SolveMedia
-class RyushareCom(XFileSharingPro):
- __name__ = "RyushareCom"
- __type__ = "hoster"
+class RyushareCom(XFSHoster):
+ __name__ = "RyushareCom"
+ __type__ = "hoster"
+ __version__ = "0.20"
+
__pattern__ = r'http://(?:www\.)?ryushare\.com/\w+'
- __version__ = "0.15"
+
__description__ = """Ryushare.com hoster plugin"""
- __author_name__ = ("zoidberg", "stickell", "quareevo")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it", "quareevo@arcor.de")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it"),
+ ("quareevo", "quareevo@arcor.de")]
- HOSTER_NAME = "ryushare.com"
- FILE_SIZE_PATTERN = r'You have requested <font color="red">[^<]+</font> \((?P<S>[\d\.]+) (?P<U>\w+)'
+ HOSTER_DOMAIN = "ryushare.com"
+
+ WAIT_PATTERN = r'You have to wait ((?P<H>\d+) hour[s]?, )?((?P<M>\d+) minute[s], )?(?P<S>\d+) second[s]'
+
+ LINK_PATTERN = r'<a href="([^"]+)">Click here to download<'
- WAIT_PATTERN = r'You have to wait ((?P<hour>\d+) hour[s]?, )?((?P<min>\d+) minute[s], )?(?P<sec>\d+) second[s]'
- LINK_PATTERN = r'(http://([^/]*?ryushare.com|\d+\.\d+\.\d+\.\d+)(:\d+/d/|/files/\w+/\w+/)[^"\'<]+)'
- SOLVEMEDIA_PATTERN = r'http:\/\/api\.solvemedia\.com\/papi\/challenge\.script\?k=(.*?)"'
def getDownloadLink(self):
retry = False
@@ -45,7 +49,7 @@ class RyushareCom(XFileSharingPro):
m = re.search(self.WAIT_PATTERN, self.html)
if m:
wait = m.groupdict(0)
- waittime = int(wait['hour']) * 60 * 60 + int(wait['min']) * 60 + int(wait['sec'])
+ waittime = int(wait['H']) * 60 * 60 + int(wait['M']) * 60 + int(wait['S'])
self.setWait(waittime, True)
retry = True
@@ -53,14 +57,9 @@ class RyushareCom(XFileSharingPro):
if retry:
self.retry()
- for _ in xrange(5):
- m = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if m is None:
- self.parseError("Error parsing captcha")
-
- captchaKey = m.group(1)
- captcha = SolveMedia(self)
- challenge, response = captcha.challenge(captchaKey)
+ for _i in xrange(5):
+ solvemedia = SolveMedia(self)
+ challenge, response = solvemedia.challenge()
inputs['adcopy_challenge'] = challenge
inputs['adcopy_response'] = response
@@ -68,12 +67,11 @@ class RyushareCom(XFileSharingPro):
self.html = self.load(self.pyfile.url, post=inputs)
if "WRONG CAPTCHA" in self.html:
self.invalidCaptcha()
- self.logInfo("Invalid Captcha")
else:
self.correctCaptcha()
break
else:
- self.fail("You have entered 5 invalid captcha codes")
+ self.fail(_("You have entered 5 invalid captcha codes"))
if "Click here to download" in self.html:
return re.search(r'<a href="([^"]+)">Click here to download</a>', self.html).group(1)
diff --git a/module/plugins/hoster/SafesharingEu.py b/module/plugins/hoster/SafesharingEu.py
new file mode 100644
index 000000000..bb6e0f646
--- /dev/null
+++ b/module/plugins/hoster/SafesharingEu.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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")]
+
+
+ HOSTER_DOMAIN = "safesharing.eu"
+
+ 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
index aef6ac1bd..64e6456a9 100644
--- a/module/plugins/hoster/SecureUploadEu.py
+++ b/module/plugins/hoster/SecureUploadEu.py
@@ -1,21 +1,23 @@
# -*- coding: utf-8 -*-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class SecureUploadEu(XFileSharingPro):
- __name__ = "SecureUploadEu"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?secureupload\.eu/(\w){12}(/\w+)'
- __version__ = "0.01"
+class SecureUploadEu(XFSHoster):
+ __name__ = "SecureUploadEu"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __pattern__ = r'https?://(?:www\.)?secureupload\.eu/\w{12}'
+
__description__ = """SecureUpload.eu hoster plugin"""
- __author_name__ = "z00nx"
- __author_mail__ = "z00nx0@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("z00nx", "z00nx0@gmail.com")]
+
- HOSTER_NAME = "secureupload.eu"
+ HOSTER_DOMAIN = "secureupload.eu"
- FILE_INFO_PATTERN = r'<h3>Downloading (?P<N>[^<]+) \((?P<S>[^<]+)\)</h3>'
- OFFLINE_PATTERN = r'The file was removed|File Not Found'
+ INFO_PATTERN = r'<h3>Downloading (?P<N>[^<]+) \((?P<S>[^<]+)\)</h3>'
getInfo = create_getInfo(SecureUploadEu)
diff --git a/module/plugins/hoster/SendmywayCom.py b/module/plugins/hoster/SendmywayCom.py
index 6de87e2b3..637098b88 100644
--- a/module/plugins/hoster/SendmywayCom.py
+++ b/module/plugins/hoster/SendmywayCom.py
@@ -1,21 +1,21 @@
# -*- coding: utf-8 -*-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class SendmywayCom(XFileSharingPro):
- __name__ = "SendmywayCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?sendmyway.com/\w{12}'
- __version__ = "0.01"
- __description__ = """SendMyWay hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+class SendmywayCom(XFSHoster):
+ __name__ = "SendmywayCom"
+ __type__ = "hoster"
+ __version__ = "0.04"
- HOSTER_NAME = "sendmyway.com"
+ __pattern__ = r'http://(?:www\.)?sendmyway\.com/\w{12}'
- FILE_NAME_PATTERN = r'<p class="file-name" ><.*?>\s*(?P<N>.+)'
- FILE_SIZE_PATTERN = r'<small>\((?P<S>\d+) bytes\)</small>'
+ __description__ = """SendMyWay.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ HOSTER_DOMAIN = "sendmyway.com"
getInfo = create_getInfo(SendmywayCom)
diff --git a/module/plugins/hoster/SendspaceCom.py b/module/plugins/hoster/SendspaceCom.py
index ea8e8d0a0..12f966e31 100644
--- a/module/plugins/hoster/SendspaceCom.py
+++ b/module/plugins/hoster/SendspaceCom.py
@@ -1,45 +1,35 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class SendspaceCom(SimpleHoster):
- __name__ = "SendspaceCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?sendspace.com/file/.*'
- __version__ = "0.13"
+ __name__ = "SendspaceCom"
+ __type__ = "hoster"
+ __version__ = "0.16"
+
+ __pattern__ = r'https?://(?:www\.)?sendspace\.com/file/\w+'
+
__description__ = """Sendspace.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<h2 class="bgray">\s*<(?:b|strong)>(?P<N>[^<]+)</'
- FILE_SIZE_PATTERN = r'<div class="file_description reverse margin_center">\s*<b>File Size:</b>\s*(?P<S>[0-9.]+)(?P<U>[kKMG])i?B\s*</div>'
+
+ 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_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>'
+
+ 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):
params = {}
- for _ in xrange(3):
+ for _i in xrange(3):
m = re.search(self.LINK_PATTERN, self.html)
if m:
if 'captcha_hash' in params:
@@ -63,10 +53,9 @@ class SendspaceCom(SimpleHoster):
self.logDebug(params)
self.html = self.load(self.pyfile.url, post=params)
else:
- self.fail("Download link not found")
+ self.fail(_("Download link not found"))
- self.logDebug("Download URL: %s" % download_url)
self.download(download_url)
-create_getInfo(SendspaceCom)
+getInfo = create_getInfo(SendspaceCom)
diff --git a/module/plugins/hoster/Share4webCom.py b/module/plugins/hoster/Share4webCom.py
index 01935ee72..4634917ad 100644
--- a/module/plugins/hoster/Share4webCom.py
+++ b/module/plugins/hoster/Share4webCom.py
@@ -5,15 +5,18 @@ from module.plugins.internal.SimpleHoster import create_getInfo
class Share4webCom(UnibytesCom):
- __name__ = "Share4webCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?share4web\.com/get/\w+'
- __version__ = "0.1"
+ __name__ = "Share4webCom"
+ __type__ = "hoster"
+ __version__ = "0.11"
+
+ __pattern__ = r'https?://(?:www\.)?share4web\.com/get/\w+'
+
__description__ = """Share4web.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- HOSTER_NAME = "share4web.com"
+ HOSTER_DOMAIN = "share4web.com"
getInfo = create_getInfo(UnibytesCom)
diff --git a/module/plugins/hoster/Share76Com.py b/module/plugins/hoster/Share76Com.py
index e1ae16242..1ac8a64e7 100644
--- a/module/plugins/hoster/Share76Com.py
+++ b/module/plugins/hoster/Share76Com.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class Share76Com(DeadHoster):
- __name__ = "Share76Com"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?share76.com/\w{12}'
+ __name__ = "Share76Com"
+ __type__ = "hoster"
__version__ = "0.04"
+
+ __pattern__ = r'http://(?:www\.)?share76\.com/\w{12}'
+
__description__ = """Share76.com hoster plugin"""
- __author_name__ = "me"
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = []
getInfo = create_getInfo(Share76Com)
diff --git a/module/plugins/hoster/ShareFilesCo.py b/module/plugins/hoster/ShareFilesCo.py
index 35f21916c..4996014d8 100644
--- a/module/plugins/hoster/ShareFilesCo.py
+++ b/module/plugins/hoster/ShareFilesCo.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class ShareFilesCo(DeadHoster):
- __name__ = "ShareFilesCo"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?sharefiles\.co/\w{12}'
+ __name__ = "ShareFilesCo"
+ __type__ = "hoster"
__version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?sharefiles\.co/\w{12}'
+
__description__ = """Sharefiles.co hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __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
index a4625b6a1..c0fd22c91 100644
--- a/module/plugins/hoster/SharebeesCom.py
+++ b/module/plugins/hoster/SharebeesCom.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class SharebeesCom(DeadHoster):
- __name__ = "SharebeesCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?sharebees.com/\w{12}'
+ __name__ = "SharebeesCom"
+ __type__ = "hoster"
__version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?sharebees\.com/\w{12}'
+
__description__ = """ShareBees hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
index a31b7c701..dc3d5093c 100644
--- a/module/plugins/hoster/ShareonlineBiz.py
+++ b/module/plugins/hoster/ShareonlineBiz.py
@@ -1,161 +1,144 @@
# -*- coding: utf-8 -*-
import re
+
from time import time
+from urllib import unquote
+from urlparse import urlparse
-from module.plugins.Hoster import Hoster
from module.network.RequestFactory import getURL
-from module.plugins.Plugin import chunks
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-def getInfo(urls):
- api_url_base = "http://api.share-online.biz/linkcheck.php"
+class ShareonlineBiz(SimpleHoster):
+ __name__ = "ShareonlineBiz"
+ __type__ = "hoster"
+ __version__ = "0.45"
- urls = [url.replace("https://", "http://") for url in urls]
+ __pattern__ = r'https?://(?:www\.)?(share-online\.biz|egoshare\.com)/(download\.php\?id=|dl/)(?P<ID>\w+)'
- for chunk in chunks(urls, 90):
- api_param_file = {"links": "\n".join(x.replace("http://www.share-online.biz/dl/", "").rstrip("/") for x in
- chunk)} # api only supports old style links
- src = getURL(api_url_base, post=api_param_file, decode=True)
- result = []
- for i, res in enumerate(src.split("\n")):
- if not res:
- continue
- fields = res.split(";")
+ __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")]
- if fields[1] == "OK":
- status = 2
- elif fields[1] in ("DELETED", "NOT FOUND"):
- status = 1
- else:
- status = 3
- result.append((fields[2], int(fields[3]), status, chunk[i]))
- yield result
+ URL_REPLACEMENTS = [(__pattern__ + ".*", "http://www.share-online.biz/dl/\g<ID>")]
-
-class ShareonlineBiz(Hoster):
- __name__ = "ShareonlineBiz"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?(share-online\.biz|egoshare\.com)/(download.php\?id=|dl/)(?P<ID>\w+)'
- __version__ = "0.40"
- __description__ = """Shareonline.biz hoster plugin"""
- __author_name__ = ("spoob", "mkaay", "zoidberg", "Walter Purcaro")
- __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de", "zoidberg@mujmail.cz", "vuolter@gmail.com")
+ RECAPTCHA_KEY = "6LdatrsSAAAAAHZrB70txiV5p-8Iv8BtVxlTtjKX"
ERROR_INFO_PATTERN = r'<p class="b">Information:</p>\s*<div>\s*<strong>(.*?)</strong>'
- def setup(self):
- # range request not working?
- # api supports resume, only one chunk
- # website isn't supporting resuming in first place
- self.file_id = re.match(self.__pattern__, self.pyfile.url).group("ID")
- self.pyfile.url = "http://www.share-online.biz/dl/" + self.file_id
- self.resumeDownload = self.premium
- self.multiDL = False
- #self.chunkLimit = 1
+ @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}
- self.check_data = None
+ if url:
+ info['pattern'] = re.match(cls.__pattern__, url).groupdict()
- def process(self, pyfile):
- if self.premium:
- self.handlePremium()
- #web-download fallback removed - didn't work anyway
- else:
- self.handleFree()
-
- # check = self.checkDownload({"failure": re.compile(self.ERROR_INFO_PATTERN)})
- # if check == "failure":
- # try:
- # self.retry(reason=self.lastCheck.group(1).decode("utf8"))
- # except:
- # self.retry(reason="Unknown error")
-
- if self.api_data:
- self.check_data = {"size": int(self.api_data['size']), "md5": self.api_data['md5']}
-
- def loadAPIData(self):
- api_url_base = "http://api.share-online.biz/linkcheck.php?md5=1"
- api_param_file = {"links": self.file_id} # api only supports old style links
- src = self.load(api_url_base, cookies=False, post=api_param_file, decode=True)
-
- fields = src.split(";")
- self.api_data = {"fileid": fields[0],
- "status": fields[1]}
- if not self.api_data['status'] == "OK":
- self.offline()
- else:
- self.api_data['filename'] = fields[2]
- self.api_data['size'] = fields[3] # in bytes
- self.api_data['md5'] = fields[4].strip().lower().replace("\n\n", "") # md5
+ field = getURL("http://api.share-online.biz/linkcheck.php",
+ get={'md5': "1"},
+ post={'links': info['pattern']['ID']},
+ decode=True).split(";")
- def handleFree(self):
- self.loadAPIData()
- self.pyfile.name = self.api_data['filename']
- self.pyfile.size = int(self.api_data['size'])
+ 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
- self.html = self.load(self.pyfile.url, cookies=True) # refer, stuff
- self.setWait(3)
- self.wait()
+ elif field[1] in ("DELETED", "NOT FOUND"):
+ info['status'] = 1
- self.html = self.load("%s/free/" % self.pyfile.url, post={"dl_free": "1", "choice": "free"}, decode=True)
- self.checkErrors()
+ return info
+
+
+ def setup(self):
+ self.resumeDownload = self.premium
+ self.multiDL = False
- m = re.search(r'var wait=(\d+);', self.html)
+ def handleCaptcha(self):
recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- challenge, response = recaptcha.challenge("6LdatrsSAAAAAHZrB70txiV5p-8Iv8BtVxlTtjKX")
+
+ for _i in xrange(5):
+ challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
+
+ m = re.search(r'var wait=(\d+);', self.html)
self.setWait(int(m.group(1)) if m else 30)
- response = 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 response == '0':
+ 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()
- break
+ return res
else:
self.invalidCaptcha()
else:
self.invalidCaptcha()
- self.fail("No valid captcha solution received")
+ self.fail(_("No valid captcha solution received"))
+
+
+ def handleFree(self):
+ self.html = self.load(self.pyfile.url, cookies=True) #: refer, stuff
+
+ self.wait(3)
+
+ self.html = self.load("%s/free/" % self.pyfile.url, post={"dl_free": "1", "choice": "free"}, decode=True)
+
+ self.checkErrors()
+
+ res = self.handleCaptcha()
+
+ download_url = res.decode("base64")
- download_url = response.decode("base64")
- self.logDebug(download_url)
if not download_url.startswith("http://"):
- self.parseError("download url")
+ self.error(_("Wrong download url"))
self.wait()
+
self.download(download_url)
- # check download
+
+
+ def checkFile(self):
+ super(ShareonlineBiz, self).checkFile()
+
check = self.checkDownload({
- "cookie": re.compile(r'<div id="dl_failure"'),
- "fail": re.compile(r"<title>Share-Online")
+ '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")
+ self.retry(5, 60, _("Cookie failure"))
+
elif check == "fail":
self.invalidCaptcha()
- self.retry(5, 5 * 60, "Download failed")
- else:
- self.correctCaptcha()
+ self.retry(5, 5 * 60, _("Download failed"))
+
def handlePremium(self): #: should be working better loading (account) api internally
self.account.getAccountInfo(self.user, True)
- src = self.load("http://api.share-online.biz/account.php",
+
+ html = self.load("http://api.share-online.biz/account.php",
{"username": self.user, "password": self.account.accounts[self.user]['password'],
- "act": "download", "lid": self.file_id})
+ "act": "download", "lid": self.info['fileid']})
self.api_data = dlinfo = {}
- for line in src.splitlines():
+
+ for line in html.splitlines():
key, value = line.split(": ")
dlinfo[key.lower()] = value
self.logDebug(dlinfo)
+
if not dlinfo['status'] == "online":
self.offline()
else:
@@ -163,33 +146,43 @@ class ShareonlineBiz(Hoster):
self.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
- err = m.group(1)
- m = re.search(self.ERROR_INFO_PATTERN, self.html)
- msg = m.group(1) if m else ""
- self.logError(err, msg or "Unknown error occurred")
+ errmsg = m.group(1).lower()
+
+ try:
+ self.logError(errmsg, re.search(self.ERROR_INFO_PATTERN, self.html).group(1))
+ except:
+ 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)
- if err == "invalid":
- self.fail(msg or "File not available")
- elif err in ("freelimit", "size", "proxy"):
- self.fail(msg or "Premium account needed")
else:
- if err in 'server':
- self.setWait(600, False)
- elif err in 'expired':
- self.setWait(30, False)
- else:
- self.setWait(300, True)
+ self.wantReconnect = True
+ self.retry(wait_time=60, reason=errmsg)
+
- self.wait()
- self.retry(max_tries=25, reason=msg)
+getInfo = create_getInfo(ShareonlineBiz)
diff --git a/module/plugins/hoster/ShareplaceCom.py b/module/plugins/hoster/ShareplaceCom.py
index cfc2807f9..ccf4bcda5 100644
--- a/module/plugins/hoster/ShareplaceCom.py
+++ b/module/plugins/hoster/ShareplaceCom.py
@@ -1,24 +1,30 @@
# -*- coding: utf-8 -*-
import re
-import urllib
+
+from urllib import unquote
+
from module.plugins.Hoster import Hoster
class ShareplaceCom(Hoster):
- __name__ = "ShareplaceCom"
- __type__ = "hoster"
- __pattern__ = r'(http://)?(?:www\.)?shareplace\.(com|org)/\?[a-zA-Z0-9]+'
+ __name__ = "ShareplaceCom"
+ __type__ = "hoster"
__version__ = "0.11"
+
+ __pattern__ = r'(http://)?(?:www\.)?shareplace\.(com|org)/\?\w+'
+
__description__ = """Shareplace.com hoster plugin"""
- __author_name__ = "ACCakut"
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = [("ACCakut", None)]
+
def process(self, pyfile):
self.pyfile = pyfile
self.prepare()
self.download(self.get_file_url())
+
def prepare(self):
if not self.file_exists():
self.offline()
@@ -27,9 +33,9 @@ class ShareplaceCom(Hoster):
wait_time = self.get_waiting_time()
self.setWait(wait_time)
- self.logDebug("%s: Waiting %d seconds." % (self.__name__, wait_time))
self.wait()
+
def get_waiting_time(self):
if not self.html:
self.download_html()
@@ -43,23 +49,26 @@ class ShareplaceCom(Hoster):
return sec
+
def download_html(self):
url = re.sub("shareplace.com\/\?", "shareplace.com//index1.php/?a=", self.pyfile.url)
self.html = self.load(url, decode=True)
+
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
url = re.search(r"var beer = '(.*?)';", self.html)
if url:
url = url.group(1)
- url = urllib.unquote(
+ url = unquote(
url.replace("http://http:/", "").replace("vvvvvvvvv", "").replace("lllllllll", "").replace(
"teletubbies", ""))
self.logDebug("URL: %s" % url)
return url
else:
- self.fail("absolute filepath could not be found. offline? ")
+ self.error(_("Absolute filepath not found"))
+
def get_file_name(self):
if not self.html:
@@ -67,6 +76,7 @@ class ShareplaceCom(Hoster):
return re.search("<title>\s*(.*?)\s*</title>", self.html).group(1)
+
def file_exists(self):
""" returns True or False
"""
diff --git a/module/plugins/hoster/SharingmatrixCom.py b/module/plugins/hoster/SharingmatrixCom.py
new file mode 100644
index 000000000..fa08a4a8f
--- /dev/null
+++ b/module/plugins/hoster/SharingmatrixCom.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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", None)]
+
+
+getInfo = create_getInfo(SharingmatrixCom)
diff --git a/module/plugins/hoster/ShragleCom.py b/module/plugins/hoster/ShragleCom.py
index a86e66972..bec30f6f2 100644
--- a/module/plugins/hoster/ShragleCom.py
+++ b/module/plugins/hoster/ShragleCom.py
@@ -4,13 +4,16 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class ShragleCom(DeadHoster):
- __name__ = "ShragleCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(cloudnator|shragle).com/files/(?P<ID>.*?)/'
+ __name__ = "ShragleCom"
+ __type__ = "hoster"
__version__ = "0.22"
+
+ __pattern__ = r'http://(?:www\.)?(cloudnator|shragle)\.com/files/(?P<ID>.+?)/'
+
__description__ = """Cloudnator.com (Shragle.com) hoster plugin"""
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+ __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
index c0be4b145..bf7c43af6 100644
--- a/module/plugins/hoster/SimplyPremiumCom.py
+++ b/module/plugins/hoster/SimplyPremiumCom.py
@@ -1,91 +1,77 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
+
from datetime import datetime, timedelta
-from module.plugins.Hoster import Hoster
-from module.plugins.hoster.UnrestrictLi import secondsToMidnight
+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.07"
+
+ __pattern__ = r'https?://.+simply-premium\.com'
-class SimplyPremiumCom(Hoster):
- __name__ = "SimplyPremiumCom"
- __version__ = "0.03"
- __type__ = "hoster"
- __pattern__ = r'https?://.*(simply-premium)\.com'
__description__ = """Simply-Premium.com hoster plugin"""
- __author_name__ = "EvolutionClip"
- __author_mail__ = "evolutionclip@live.de"
+ __license__ = "GPLv3"
+ __authors__ = [("EvolutionClip", "evolutionclip@live.de")]
+
def setup(self):
- self.chunkLimit = 16
+ self.chunkLimit = 16
self.resumeDownload = False
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "Simply-Premium.com")
- self.fail("No Simply-Premium.com account provided")
+
+ def handlePremium(self):
+ for i in xrange(5):
+ page = self.load("http://www.simply-premium.com/premium.php", get={'info': "", 'link': self.pyfile.url})
+ self.logDebug("JSON data: " + page)
+ if page != '':
+ break
else:
- self.logDebug("Old URL: %s" % pyfile.url)
- for i in xrange(5):
- page = self.load('http://www.simply-premium.com/premium.php?info&link=' + pyfile.url)
- self.logDebug("JSON data: " + page)
- if page != '':
- break
- else:
- self.logInfo("Unable to get API data, waiting 1 minute and retry")
- self.retry(5, 60, "Unable to get API data")
-
- if '<valid>0</valid>' in page or (
- "You are not allowed to download from this host" in page and self.premium):
- self.account.relogin(self.user)
- self.retry()
- elif "NOTFOUND" in page:
- self.offline()
- elif "downloadlimit" in page:
- self.logWarning("Reached maximum connctions")
- self.retry(5, 60, "Reached maximum connctions")
- elif "trafficlimit" in page:
- self.logWarning("Reached daily limit for this host")
- self.retry(1, secondsToMidnight(gmt=2), "Daily limit for this host reached")
- elif "hostererror" in page:
- self.logWarning("Hoster temporarily unavailable, waiting 1 minute and retry")
- self.retry(5, 60, "Hoster is temporarily unavailable")
- #page = json_loads(page)
- #new_url = page.keys()[0]
- #self.api_data = page[new_url]
-
- try:
- self.pyfile.name = re.search(r'<name>([^<]+)</name>', page).group(1)
- except AttributeError:
- self.pyfile.name = ""
-
- try:
- self.pyfile.size = re.search(r'<size>(\d+)</size>', page).group(1)
- except AttributeError:
- self.pyfile.size = 0
-
- try:
- new_url = re.search(r'<download>([^<]+)</download>', page).group(1)
- except AttributeError:
- new_url = 'http://www.simply-premium.com/premium.php?link=' + pyfile.url
-
- if new_url != pyfile.url:
- self.logDebug("New URL: " + new_url)
-
- self.download(new_url, disposition=True)
+ self.logInfo(_("Unable to get API data, waiting 1 minute and retry"))
+ self.retry(5, 60, "Unable to get API data")
+
+ if '<valid>0</valid>' in page or (
+ "You are not allowed to download from this host" in page and self.premium):
+ self.account.relogin(self.user)
+ self.retry()
+
+ elif "NOTFOUND" in page:
+ self.offline()
+
+ elif "downloadlimit" in page:
+ self.logWarning(_("Reached maximum connctions"))
+ self.retry(5, 60, "Reached maximum connctions")
+
+ elif "trafficlimit" in page:
+ 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 page:
+ self.logWarning(_("Hoster temporarily unavailable, waiting 1 minute and retry"))
+ self.retry(5, 60, "Hoster is temporarily unavailable")
+
+ try:
+ self.pyfile.name = re.search(r'<name>([^<]+)</name>', page).group(1)
+ except AttributeError:
+ self.pyfile.name = ""
+
+ try:
+ self.pyfile.size = re.search(r'<size>(\d+)</size>', page).group(1)
+ except AttributeError:
+ self.pyfile.size = 0
+
+ try:
+ self.link = re.search(r'<download>([^<]+)</download>', page).group(1)
+ except AttributeError:
+ self.link = 'http://www.simply-premium.com/premium.php?link=' + self.pyfile.url
+
+ if self.link != self.pyfile.url:
+ self.logDebug("New URL: " + self.link)
+
+
+getInfo = create_getInfo(SimplyPremiumCom)
diff --git a/module/plugins/hoster/SimplydebridCom.py b/module/plugins/hoster/SimplydebridCom.py
index 2aab12e04..5e6b47efc 100644
--- a/module/plugins/hoster/SimplydebridCom.py
+++ b/module/plugins/hoster/SimplydebridCom.py
@@ -2,58 +2,62 @@
import re
-from module.plugins.Hoster import Hoster
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
-class SimplydebridCom(Hoster):
- __name__ = "SimplydebridCom"
- __version__ = "0.1"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/sd.php/*'
+class SimplydebridCom(MultiHoster):
+ __name__ = "SimplydebridCom"
+ __type__ = "hoster"
+ __version__ = "0.14"
+
+ __pattern__ = r'http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/sd\.php'
+
__description__ = """Simply-debrid.com hoster plugin"""
- __author_name__ = "Kagenoshin"
- __author_mail__ = "kagenoshin@gmx.ch"
+ __license__ = "GPLv3"
+ __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")]
- def setup(self):
- self.resumeDownload = self.multiDL = True
- self.chunkLimit = 1
- def process(self, pyfile):
- if not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "simply-debrid.com")
- self.fail("No simply-debrid.com account provided")
+ def setup(self):
+ self.resumeDownload = True
+ self.multiDL = True
+ self.chunkLimit = 1
- self.logDebug("Old URL: %s" % pyfile.url)
+ def handlePremium(self):
#fix the links for simply-debrid.com!
- new_url = pyfile.url
- new_url = new_url.replace("clz.to", "cloudzer.net/file")
- new_url = new_url.replace("http://share-online", "http://www.share-online")
- new_url = new_url.replace("ul.to", "uploaded.net/file")
- new_url = new_url.replace("uploaded.com", "uploaded.net")
- new_url = new_url.replace("filerio.com", "filerio.in")
- new_url = new_url.replace("lumfile.com", "lumfile.se")
- if('fileparadox' in new_url):
- new_url = new_url.replace("http://", "https://")
-
- if re.match(self.__pattern__, new_url):
- new_url = new_url
-
- self.logDebug("New URL: %s" % new_url)
-
- if not re.match(self.__pattern__, new_url):
- page = self.load('http://simply-debrid.com/api.php', get={'dl': new_url}) # +'&u='+self.user+'&p='+self.account.getAccountData(self.user)['password'])
+ self.link = self.pyfile.url
+ self.link = self.link.replace("clz.to", "cloudzer.net/file")
+ self.link = self.link.replace("http://share-online", "http://www.share-online")
+ self.link = self.link.replace("ul.to", "uploaded.net/file")
+ self.link = self.link.replace("uploaded.com", "uploaded.net")
+ self.link = self.link.replace("filerio.com", "filerio.in")
+ self.link = self.link.replace("lumfile.com", "lumfile.se")
+
+ if('fileparadox' in self.link):
+ self.link = self.link.replace("http://", "https://")
+
+ if re.match(self.__pattern__, self.link):
+ self.link = self.link
+
+ self.logDebug("New URL: %s" % self.link)
+
+ if not re.match(self.__pattern__, self.link):
+ page = self.load("http://simply-debrid.com/api.php", get={'dl': self.link}) # +'&u='+self.user+'&p='+self.account.getAccountData(self.user)['password'])
if 'tiger Link' in page or 'Invalid Link' in page or ('API' in page and 'ERROR' in page):
- self.fail('Unable to unrestrict link')
- new_url = page
+ self.fail(_("Unable to unrestrict link"))
+ self.link = page
self.setWait(5)
self.wait()
- self.logDebug("Unrestricted URL: " + new_url)
- self.download(new_url, disposition=True)
+
+ def checkFile(self):
+ super(SimplydebridCom, self).checkFile()
check = self.checkDownload({"bad1": "No address associated with hostname", "bad2": "<html"})
if check == "bad1" or check == "bad2":
self.retry(24, 3 * 60, "Bad file downloaded")
+
+
+getInfo = create_getInfo(SimplydebridCom)
diff --git a/module/plugins/hoster/SockshareCom.py b/module/plugins/hoster/SockshareCom.py
index 61df428db..aabb8dcd1 100644
--- a/module/plugins/hoster/SockshareCom.py
+++ b/module/plugins/hoster/SockshareCom.py
@@ -1,88 +1,20 @@
# -*- coding: utf-8 -*-
-import re
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-from os import rename
-from module.plugins.hoster.UnrestrictLi import secondsToMidnight
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-
-
-class SockshareCom(SimpleHoster):
- __name__ = "SockshareCom"
- __version__ = "0.04"
- __type__ = "hoster"
+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"""
- __author_name__ = ("jeix", "stickell", "Walter Purcaro")
- __author_mail__ = ("jeix@hasnomail.de", "l.stickell@yahoo.it", "vuolter@gmail.com")
-
- FILE_INFO_PATTERN = r'site-content">\s*<h1>(?P<N>.+)<strong>\( (?P<S>[^)]+) \)</strong></h1>'
- OFFLINE_PATTERN = r'>This file doesn\'t exist, or has been removed.<'
- TEMP_OFFLINE_PATTERN = r'(>This content server has been temporarily disabled for upgrades|Try again soon\\. You can still download it below\\.<)'
-
- FILE_URL_REPLACEMENTS = [(__pattern__, r'http://www.sockshare.com/file/\g<ID>')]
-
-
- def setup(self):
- self.multiDL = self.resumeDownload = True
- self.chunkLimit = -1
-
- def handleFree(self):
- name = self.pyfile.name
- link = self._getLink()
- self.logDebug("Direct link: " + link)
- self.download(link, disposition=True)
- self.processName(name)
-
- def _getLink(self):
- hash_data = re.search(r'<input type="hidden" value="([a-z0-9]+)" name="hash">', self.html)
- if not hash_data:
- self.parseError("Unable to detect hash")
-
- post_data = {"hash": hash_data.group(1), "confirm": "Continue+as+Free+User"}
- self.html = self.load(self.pyfile.url, post=post_data)
- if ">You have exceeded the daily stream limit for your country\\. You can wait until tomorrow" in self.html:
- self.logWarning("You have exceeded your daily stream limit for today")
- self.wait(secondsToMidnight(gmt=2), True)
- elif re.search(self.TEMP_OFFLINE_PATTERN, self.html):
- self.retry(wait_time=2 * 60 * 60, reason="Server temporarily offline") # 2 hours wait
-
- patterns = (r'(/get_file\.php\?id=[A-Z0-9]+&key=[a-zA-Z0-9=]+&original=1)',
- r'(/get_file\.php\?download=[A-Z0-9]+&key=[a-z0-9]+)',
- r'(/get_file\.php\?download=[A-Z0-9]+&key=[a-z0-9]+&original=1)',
- r'<a href="/gopro\.php">Tired of ads and waiting\? Go Pro!</a>[\t\n\rn ]+</div>[\t\n\rn ]+<a href="(/.*?)"')
- for pattern in patterns:
- link = re.search(pattern, self.html)
- if link:
- break
- else:
- link = re.search(r"playlist: '(/get_file\.php\?stream=[a-zA-Z0-9=]+)'", self.html)
- if link:
- self.html = self.load("http://www.sockshare.com" + link.group(1))
- link = re.search(r'media:content url="(http://.*?)"', self.html)
- if link is None:
- link = re.search(r'\"(http://media\\-b\\d+\\.sockshare\\.com/download/\\d+/.*?)\"', self.html)
- else:
- self.parseError('Unable to detect a download link')
-
- link = link.group(1).replace("&amp;", "&")
- if link.startswith("http://"):
- return link
- else:
- return "http://www.sockshare.com" + link
-
- def processName(self, name_old):
- name = self.pyfile.name
- if name <= name_old:
- return
- name_new = re.sub(r'\.[^.]+$', "", name_old) + name[len(name_old):]
- filename = self.lastDownload
- self.pyfile.name = name_new
- rename(filename, filename.rsplit(name)[0] + name_new)
- self.logInfo("%(name)s renamed to %(newname)s" % {"name": name, "newname": name_new})
+ __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/SoundcloudCom.py b/module/plugins/hoster/SoundcloudCom.py
index 75a1cffeb..3eb546604 100644
--- a/module/plugins/hoster/SoundcloudCom.py
+++ b/module/plugins/hoster/SoundcloudCom.py
@@ -1,44 +1,47 @@
# -*- coding: utf-8 -*-
-import re
import pycurl
+import re
from module.plugins.Hoster import Hoster
class SoundcloudCom(Hoster):
- __name__ = "SoundcloudCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?soundcloud\.com/(?P<UID>.*?)/(?P<SID>.*)'
- __version__ = "0.1"
+ __name__ = "SoundcloudCom"
+ __type__ = "hoster"
+ __version__ = "0.10"
+
+ __pattern__ = r'https?://(?:www\.)?soundcloud\.com/(?P<UID>.+?)/(?P<SID>.+)'
+
__description__ = """SoundCloud.com hoster plugin"""
- __author_name__ = "Peekayy"
- __author_mail__ = "peekayy.dev@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Peekayy", "peekayy.dev@gmail.com")]
+
def process(self, pyfile):
# default UserAgent of HTTPRequest fails for this hoster so we use this one
self.req.http.c.setopt(pycurl.USERAGENT, 'Mozilla/5.0')
page = self.load(pyfile.url)
- m = re.search(r'<div class="haudio.*?large.*?" data-sc-track="(?P<ID>[0-9]*)"', page)
+ m = re.search(r'<div class="haudio.*?large.*?" data-sc-track="(?P<ID>\d*)"', page)
songId = clientId = ""
if m:
- songId = m.group("ID")
+ songId = m.group('ID')
if len(songId) <= 0:
- self.logError("Could not find song id")
+ self.logError(_("Could not find song id"))
self.offline()
else:
m = re.search(r'"clientID":"(?P<CID>.*?)"', page)
if m:
- clientId = m.group("CID")
+ clientId = m.group('CID')
if len(clientId) <= 0:
clientId = "b45b1aa10f1ac2941910a7f0d10f8e28"
m = re.search(r'<em itemprop="name">\s(?P<TITLE>.*?)\s</em>', page)
if m:
- pyfile.name = m.group("TITLE") + ".mp3"
+ pyfile.name = m.group('TITLE') + ".mp3"
else:
- pyfile.name = re.match(self.__pattern__, pyfile.url).group("SID") + ".mp3"
+ pyfile.name = re.match(self.__pattern__, pyfile.url).group('SID') + ".mp3"
# url to retrieve the actual song url
page = self.load("https://api.sndcdn.com/i1/tracks/%s/streams" % songId, get={"client_id": clientId})
@@ -46,7 +49,7 @@ class SoundcloudCom(Hoster):
# for now we choose the first stream found in all cases
# it could be improved if relevant for this hoster
streams = [
- (result.group("QUALITY"), result.group("URL"))
+ (result.group('QUALITY'), result.group('URL'))
for result in re.finditer(r'"(?P<QUALITY>.*?)":"(?P<URL>.*?)"', page)
]
self.logDebug("Found Streams", streams)
diff --git a/module/plugins/hoster/SpeedLoadOrg.py b/module/plugins/hoster/SpeedLoadOrg.py
index 76ab52868..a13220eab 100644
--- a/module/plugins/hoster/SpeedLoadOrg.py
+++ b/module/plugins/hoster/SpeedLoadOrg.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class SpeedLoadOrg(DeadHoster):
- __name__ = "SpeedLoadOrg"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?speedload\.org/(?P<ID>\w+)'
+ __name__ = "SpeedLoadOrg"
+ __type__ = "hoster"
__version__ = "1.02"
+
+ __pattern__ = r'http://(?:www\.)?speedload\.org/(?P<ID>\w+)'
+
__description__ = """Speedload.org hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __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
index df66a17e2..f23c8d4c7 100644
--- a/module/plugins/hoster/SpeedfileCz.py
+++ b/module/plugins/hoster/SpeedfileCz.py
@@ -1,31 +1,18 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class SpeedfileCz(DeadHoster):
- __name__ = "SpeedFileCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?speedfile.cz/.*'
+ __name__ = "SpeedFileCz"
+ __type__ = "hoster"
__version__ = "0.32"
+
+ __pattern__ = r'http://(?:www\.)?speedfile\.cz/.+'
+
__description__ = """Speedfile.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
new file mode 100644
index 000000000..fa54d6060
--- /dev/null
+++ b/module/plugins/hoster/SpeedyshareCom.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+#
+# Test links:
+# http://speedy.sh/ep2qY/Zapp-Brannigan.jpg
+
+import re
+
+from urlparse import urljoin
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class SpeedyshareCom(SimpleHoster):
+ __name__ = "SpeedyshareCom"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
+ __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_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):
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ self.error(_("Download link not found"))
+
+ dl_link = urljoin("http://www.speedyshare.com", m.group(1))
+ self.download(dl_link, disposition=True)
+
+ check = self.checkDownload({'html': re.compile("html")})
+ if check == "html":
+ self.error(_("Downloaded file is an html page"))
+
+
+getInfo = create_getInfo(SpeedyshareCom)
diff --git a/module/plugins/hoster/StorageTo.py b/module/plugins/hoster/StorageTo.py
new file mode 100644
index 000000000..bedc2934f
--- /dev/null
+++ b/module/plugins/hoster/StorageTo.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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/StreamCz.py b/module/plugins/hoster/StreamCz.py
index e68130389..11d4efcdb 100644
--- a/module/plugins/hoster/StreamCz.py
+++ b/module/plugins/hoster/StreamCz.py
@@ -1,24 +1,9 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from module.plugins.Hoster import Hoster
from module.network.RequestFactory import getURL
+from module.plugins.Hoster import Hoster
def getInfo(urls):
@@ -36,28 +21,29 @@ def getInfo(urls):
class StreamCz(Hoster):
- __name__ = "StreamCz"
- __version__ = "0.2"
- __type__ = "hoster"
+ __name__ = "StreamCz"
+ __type__ = "hoster"
+ __version__ = "0.20"
- __pattern__ = r'https?://(?:www\.)?stream\.cz/[^/]+/\d+.*'
+ __pattern__ = r'https?://(?:www\.)?stream\.cz/[^/]+/\d+'
__description__ = """Stream.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_NAME_PATTERN = r'<link rel="video_src" href="http://www.stream.cz/\w+/(\d+)-([^"]+)" />'
+ NAME_PATTERN = r'<link rel="video_src" href="http://www\.stream\.cz/\w+/(\d+)-([^"]+)" />'
OFFLINE_PATTERN = r'<h1 class="commonTitle">Str.nku nebylo mo.n. nal.zt \(404\)</h1>'
CDN_PATTERN = r'<param name="flashvars" value="[^"]*&id=(?P<ID>\d+)(?:&cdnLQ=(?P<cdnLQ>\d*))?(?:&cdnHQ=(?P<cdnHQ>\d*))?(?:&cdnHD=(?P<cdnHD>\d*))?&'
def setup(self):
- self.multiDL = True
self.resumeDownload = True
+ self.multiDL = True
- def process(self, pyfile):
+ def process(self, pyfile):
self.html = self.load(pyfile.url, decode=True)
if re.search(self.OFFLINE_PATTERN, self.html):
@@ -65,7 +51,7 @@ class StreamCz(Hoster):
m = re.search(self.CDN_PATTERN, self.html)
if m is None:
- self.fail("Parse error (CDN)")
+ self.error(_("CDN_PATTERN not found"))
cdn = m.groupdict()
self.logDebug(cdn)
for cdnkey in ("cdnHD", "cdnHQ", "cdnLQ"):
@@ -73,13 +59,13 @@ class StreamCz(Hoster):
cdnid = cdn[cdnkey]
break
else:
- self.fail("Stream URL not found")
+ self.fail(_("Stream URL not found"))
- m = re.search(self.FILE_NAME_PATTERN, self.html)
+ m = re.search(self.NAME_PATTERN, self.html)
if m is None:
- self.fail("Parse error (NAME)")
+ self.error(_("NAME_PATTERN not found"))
pyfile.name = "%s-%s.%s.mp4" % (m.group(2), m.group(1), cdnkey[-2:])
download_url = "http://cdn-dispatcher.stream.cz/?id=" + cdnid
- self.logInfo("STREAM (%s): %s" % (cdnkey[-2:], download_url))
+ self.logInfo(_("STREAM: %s") % cdnkey[-2:], download_url)
self.download(download_url)
diff --git a/module/plugins/hoster/StreamcloudEu.py b/module/plugins/hoster/StreamcloudEu.py
index 3cbf015c9..4f854a99d 100644
--- a/module/plugins/hoster/StreamcloudEu.py
+++ b/module/plugins/hoster/StreamcloudEu.py
@@ -1,120 +1,31 @@
# -*- coding: utf-8 -*-
-from time import sleep
import re
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-from module.network.HTTPRequest import HTTPRequest
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-class StreamcloudEu(XFileSharingPro):
- __name__ = "StreamcloudEu"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?streamcloud\.eu/\S+'
- __version__ = "0.04"
- __description__ = """Streamcloud.eu hoster plugin"""
- __author_name__ = "seoester"
- __author_mail__ = "seoester@googlemail.com"
-
- HOSTER_NAME = "streamcloud.eu"
-
- LINK_PATTERN = r'file: "(http://(stor|cdn)\d+\.streamcloud.eu:?\d*/.*/video\.(mp4|flv))",'
-
- def setup(self):
- super(StreamcloudEu, self).setup()
- self.multiDL = True
-
- def getDownloadLink(self):
- m = re.search(self.LINK_PATTERN, self.html, re.S)
- if m:
- return m.group(1)
-
- for i in xrange(5):
- self.logDebug("Getting download link: #%d" % i)
- data = self.getPostParameters()
- httpRequest = HTTPRequest(options=self.req.options)
- httpRequest.cj = self.req.cj
- sleep(10)
- self.html = httpRequest.load(self.pyfile.url, post=data, referer=False, cookies=True, decode=True)
- self.header = httpRequest.header
-
- m = re.search("Location\s*:\s*(.*)", self.header, re.I)
- if m:
- break
-
- m = re.search(self.LINK_PATTERN, self.html, re.S)
- if m:
- break
-
- else:
- if self.errmsg and 'captcha' in self.errmsg:
- self.fail("No valid captcha code entered")
- else:
- self.fail("Download link not found")
+class StreamcloudEu(XFSHoster):
+ __name__ = "StreamcloudEu"
+ __type__ = "hoster"
+ __version__ = "0.09"
- return m.group(1)
+ __pattern__ = r'http://(?:www\.)?streamcloud\.eu/\w{12}'
- def getPostParameters(self):
- for i in xrange(3):
- if not self.errmsg:
- self.checkErrors()
-
- if hasattr(self, "FORM_PATTERN"):
- action, inputs = self.parseHtmlForm(self.FORM_PATTERN)
- else:
- action, inputs = self.parseHtmlForm(input_names={"op": re.compile("^download")})
-
- if not inputs:
- action, inputs = self.parseHtmlForm('F1')
- if not inputs:
- if self.errmsg:
- self.retry()
- else:
- self.parseError("Form not found")
-
- self.logDebug(self.HOSTER_NAME, inputs)
-
- if 'op' in inputs and inputs['op'] in ("download1", "download2", "download3"):
- if "password" in inputs:
- if self.passwords:
- inputs['password'] = self.passwords.pop(0)
- else:
- self.fail("No or invalid passport")
-
- if not self.premium:
- m = re.search(self.WAIT_PATTERN, self.html)
- if m:
- wait_time = int(m.group(1)) + 1
- self.setWait(wait_time, False)
- else:
- wait_time = 0
-
- self.captcha = self.handleCaptcha(inputs)
-
- if wait_time:
- self.wait()
+ __description__ = """Streamcloud.eu hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("seoester", "seoester@googlemail.com")]
- self.errmsg = None
- self.logDebug("getPostParameters {0}".format(i))
- return inputs
- else:
- inputs['referer'] = self.pyfile.url
+ HOSTER_DOMAIN = "streamcloud.eu"
- if self.premium:
- inputs['method_premium'] = "Premium Download"
- if 'method_free' in inputs:
- del inputs['method_free']
- else:
- inputs['method_free'] = "Free Download"
- if 'method_premium' in inputs:
- del inputs['method_premium']
+ LINK_PATTERN = r'file: "(http://(stor|cdn)\d+\.streamcloud\.eu:?\d*/.*/video\.(mp4|flv))",'
- self.html = self.load(self.pyfile.url, post=inputs, ref=False)
- self.errmsg = None
- else:
- self.parseError('FORM: %s' % (inputs['op'] if 'op' in inputs else 'UNKNOWN'))
+ 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
index 52708d045..258ec7d3e 100644
--- a/module/plugins/hoster/TurbobitNet.py
+++ b/module/plugins/hoster/TurbobitNet.py
@@ -1,59 +1,49 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-import re
import random
-from urllib import quote
-from binascii import hexlify, unhexlify
+import re
import time
-from pycurl import HTTPHEADER
from Crypto.Cipher import ARC4
+from binascii import hexlify, unhexlify
+from pycurl import HTTPHEADER
+from urllib import quote
+
from module.network.RequestFactory import getURL
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp
class TurbobitNet(SimpleHoster):
- __name__ = "TurbobitNet"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(turbobit.net|unextfiles.com)/(?!download/folder/)(?:download/free/)?(?P<ID>\w+).*'
- __version__ = "0.11"
- __description__ = """Turbobit.net plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
- FILE_INFO_PATTERN = r"<span class='file-icon1[^>]*>(?P<N>[^<]+)</span>\s*\((?P<S>[^\)]+)\)\s*</h1>" #: long filenames are shortened
- FILE_NAME_PATTERN = r'<meta name="keywords" content="\s+(?P<N>[^,]+)' #: full name but missing on page2
+ __name__ = "TurbobitNet"
+ __type__ = "hoster"
+ __version__ = "0.16"
+
+ __pattern__ = r'http://(?:www\.)?turbobit\.net/(?:download/free/)?(?P<ID>\w+)'
+
+ __description__ = """ Turbobit.net hoster plugin """
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("prOq", None)]
+
+
+ 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'
- FILE_URL_REPLACEMENTS = [(r"http://(?:www\.)?(turbobit.net|unextfiles.com)/(?:download/free/)?(?P<ID>\w+).*",
- "http://turbobit.net/\g<ID>.html")]
- SH_COOKIES = [(".turbobit.net", "user_lang", "en")]
+ LINK_PATTERN = r'(/download/redirect/[^"\']+)'
+ LIMIT_WAIT_PATTERN = r'<div id=\'timeout\'>(\d+)<'
- LINK_PATTERN = r'(?P<url>/download/redirect/[^"\']+)'
- LIMIT_WAIT_PATTERN = r'<div id="time-limit-text">\s*.*?<span id=\'timeout\'>(\d+)</span>'
- CAPTCHA_KEY_PATTERN = r'src="http://api\.recaptcha\.net/challenge\?k=([^"]+)"'
- CAPTCHA_SRC_PATTERN = r'<img alt="Captcha" src="(.*?)"'
+ CAPTCHA_PATTERN = r'<img alt="Captcha" src="(.+?)"'
def handleFree(self):
- self.url = "http://turbobit.net/download/free/%s" % self.file_info['ID']
- self.html = self.load(self.url)
+ self.url = "http://turbobit.net/download/free/%s" % self.info['pattern']['ID']
+ self.html = self.load(self.url, ref=True, decode=True)
rtUpdate = self.getRtUpdate()
@@ -66,8 +56,9 @@ class TurbobitNet(SimpleHoster):
self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"])
self.downloadFile()
+
def solveCaptcha(self):
- for _ in xrange(5):
+ for _i in xrange(5):
m = re.search(self.LIMIT_WAIT_PATTERN, self.html)
if m:
wait_time = int(m.group(1))
@@ -76,69 +67,70 @@ class TurbobitNet(SimpleHoster):
action, inputs = self.parseHtmlForm("action='#'")
if not inputs:
- self.parseError("captcha form")
+ self.error(_("Captcha form not found"))
self.logDebug(inputs)
if inputs['captcha_type'] == 'recaptcha':
recaptcha = ReCaptcha(self)
- m = re.search(self.CAPTCHA_KEY_PATTERN, self.html)
- captcha_key = m.group(1) if m else '6LcTGLoSAAAAAHCWY9TTIrQfjUlxu6kZlTYP50_c'
- inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(
- captcha_key)
+ inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge()
else:
- m = re.search(self.CAPTCHA_SRC_PATTERN, self.html)
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
if m is None:
- self.parseError('captcha')
+ 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 not "<div class='download-timer-header'>" in self.html:
+ if '<div class="captcha-error">Incorrect, try again!<' in self.html:
self.invalidCaptcha()
else:
self.correctCaptcha()
break
else:
- self.fail("Invalid captcha")
+ 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():
+ 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
+ # 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.logDebug("rtUpdate")
self.setStorage("rtUpdate", rtUpdate)
self.setStorage("timestamp", timestamp())
self.setStorage("version", self.__version__)
else:
- self.logError("Unable to download, wait for update...")
+ 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)
- url = "http://turbobit.net%s%s" % (m.groups() if m else (
- '/files/timeout.js?ver=', ''.join(random.choice('0123456789ABCDEF') for _ in xrange(32))))
+ 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.file_info['ID'], b, quote(fun), rtUpdate)
+ self.info['pattern']['ID'], b, quote(fun), rtUpdate)
try:
out = self.js.eval(self.jscode)
@@ -153,26 +145,28 @@ class TurbobitNet(SimpleHoster):
self.delStorage("rtUpdate")
self.retry()
+
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)
+
def handlePremium(self):
self.logDebug("Premium download as user %s" % self.user)
- self.html = self.load(self.pyfile.url) # Useless in 0.5
self.downloadFile()
+
def downloadFile(self):
m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.parseError("download link")
- self.url = "http://turbobit.net" + m.group('url')
- self.logDebug(self.url)
+ self.error(_("Download link not found"))
+ self.url = "http://turbobit.net" + m.group(1)
self.download(self.url)
diff --git a/module/plugins/hoster/TurbouploadCom.py b/module/plugins/hoster/TurbouploadCom.py
index a54e963d9..f0893cef6 100644
--- a/module/plugins/hoster/TurbouploadCom.py
+++ b/module/plugins/hoster/TurbouploadCom.py
@@ -1,31 +1,18 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class TurbouploadCom(DeadHoster):
- __name__ = "TurbouploadCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?turboupload.com/(\w+).*'
+ __name__ = "TurbouploadCom"
+ __type__ = "hoster"
__version__ = "0.03"
+
+ __pattern__ = r'http://(?:www\.)?turboupload\.com/(\w+)'
+
__description__ = """Turboupload.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __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
index f42685a63..a4e352956 100644
--- a/module/plugins/hoster/TusfilesNet.py
+++ b/module/plugins/hoster/TusfilesNet.py
@@ -1,42 +1,35 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-
-
-class TusfilesNet(XFileSharingPro):
- __name__ = "TusfilesNet"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?tusfiles\.net/(?P<ID>\w+)'
- __version__ = "0.03"
+
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+
+class TusfilesNet(XFSHoster):
+ __name__ = "TusfilesNet"
+ __type__ = "hoster"
+ __version__ = "0.08"
+
+ __pattern__ = r'https?://(?:www\.)?tusfiles\.net/\w{12}'
+
__description__ = """Tusfiles.net hoster plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com"),
+ ("guidobelix", "guidobelix@hotmail.it")]
+
- HOSTER_NAME = "tusfiles.net"
+ HOSTER_DOMAIN = "tusfiles.net"
- FILE_INFO_PATTERN = r'\](?P<N>.+) - (?P<S>[\d.]+) (?P<U>\w+)\['
- OFFLINE_PATTERN = r'>File Not Found|<Title>TusFiles - Fast Sharing Files!'
+ 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'
- SH_COOKIES = [(".tusfiles.net", "lang", "english")]
def setup(self):
- self.multiDL = False
- self.chunkLimit = -1
+ self.multiDL = False
+ self.chunkLimit = -1
self.resumeDownload = True
+ def handlePremium(self):
+ return self.handleFree()
+
+
getInfo = create_getInfo(TusfilesNet)
diff --git a/module/plugins/hoster/TwoSharedCom.py b/module/plugins/hoster/TwoSharedCom.py
index 1f040dfc2..1dd67f974 100644
--- a/module/plugins/hoster/TwoSharedCom.py
+++ b/module/plugins/hoster/TwoSharedCom.py
@@ -6,31 +6,35 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class TwoSharedCom(SimpleHoster):
- __name__ = "TwoSharedCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?2shared.com/(account/)?(download|get|file|document|photo|video|audio)/.*'
- __version__ = "0.11"
+ __name__ = "TwoSharedCom"
+ __type__ = "hoster"
+ __version__ = "0.12"
+
+ __pattern__ = r'http://(?:www\.)?2shared\.com/(account/)?(download|get|file|document|photo|video|audio)/.+'
+
__description__ = """2Shared.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_NAME_PATTERN = r'<h1>(?P<N>.*)</h1>'
- FILE_SIZE_PATTERN = r'<span class="dtitle">File size:</span>\s*(?P<S>[0-9,.]+) (?P<U>[kKMG])i?B'
+ 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_PATTERN = r"window.location ='([^']+)';"
+ LINK_PATTERN = r'window.location =\'(.+?)\';'
def setup(self):
- self.resumeDownload = self.multiDL = True
+ self.resumeDownload = True
+ self.multiDL = True
+
def handleFree(self):
m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.parseError('Download link')
- link = m.group(1)
- self.logDebug("Download URL %s" % link)
+ self.error(_("Download link"))
+ link = m.group(1)
self.download(link)
diff --git a/module/plugins/hoster/UlozTo.py b/module/plugins/hoster/UlozTo.py
index 2b68bedf7..6b84a5e1b 100644
--- a/module/plugins/hoster/UlozTo.py
+++ b/module/plugins/hoster/UlozTo.py
@@ -1,24 +1,11 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
import time
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
from module.common.json_layer import json_loads
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
def convertDecimalPrefix(m):
# decimal prefixes used in filesize and traffic
@@ -26,63 +13,71 @@ def convertDecimalPrefix(m):
class UlozTo(SimpleHoster):
- __name__ = "UlozTo"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj.cz|zachowajto.pl)/(?:live/)?(?P<id>\w+/[^/?]*)'
- __version__ = "0.98"
+ __name__ = "UlozTo"
+ __type__ = "hoster"
+ __version__ = "1.01"
+
+ __pattern__ = r'http://(?:www\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj\.cz|zachowajto\.pl)/(?:live/)?(?P<ID>\w+/[^/?]*)'
+
__description__ = """Uloz.to hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_INFO_PATTERN = r'<p>File <strong>(?P<N>[^<]+)</strong> is password protected</p>'
- FILE_NAME_PATTERN = r'<title>(?P<N>[^<]+) \| Uloz.to</title>'
- FILE_SIZE_PATTERN = r'<span id="fileSize">.*?(?P<S>[0-9.]+\s[kMG]?B)</span>'
+
+ 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>'
- FILE_SIZE_REPLACEMENTS = [('([0-9.]+)\s([kMG])B', convertDecimalPrefix)]
- FILE_URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "www.ulozto.net")]
+ URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "www.ulozto.net")]
+ SIZE_REPLACEMENTS = [('([\d.]+)\s([kMG])B', convertDecimalPrefix)]
- ADULT_PATTERN = r'<form action="(?P<link>[^\"]*)" method="post" id="frm-askAgeForm">'
- PASSWD_PATTERN = r'<div class="passwordProtectedFile">'
+ 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">'
- FREE_URL_PATTERN = r'<div class="freeDownloadForm"><form action="([^"]+)"'
+ TOKEN_PATTERN = r'<input type="hidden" name="_token_" .*?value="(.+?)"'
+
+ FREE_URL_PATTERN = r'<div class="freeDownloadForm"><form action="([^"]+)"'
PREMIUM_URL_PATTERN = r'<div class="downloadForm"><form action="([^"]+)"'
- TOKEN_PATTERN = r'<input type="hidden" name="_token_" id="[^\"]*" value="(?P<token>[^\"]*)" />'
def setup(self):
- self.multiDL = self.premium
+ 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. Proceeding..")
+ self.logInfo(_("Adult content confirmation needed"))
m = re.search(self.TOKEN_PATTERN, self.html)
if m is None:
- self.parseError('TOKEN')
+ 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)
- passwords = self.getPassword().splitlines()
- while self.PASSWD_PATTERN in self.html:
- if passwords:
- password = passwords.pop(0)
- self.logInfo("Password protected link, trying " + password)
+ 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 or incorrect password")
+ self.fail(_("No password found"))
if re.search(self.VIPLINK_PATTERN, self.html):
self.html = self.load(pyfile.url, get={"disclaimer": "1"})
- self.file_info = self.getFileInfo()
+ self.getFileInfo()
if self.premium and self.checkTrafficLeft():
self.handlePremium()
@@ -91,19 +86,20 @@ class UlozTo(SimpleHoster):
self.doCheckDownload()
+
def handleFree(self):
action, inputs = self.parseHtmlForm('id="frm-downloadDialog-freeDownloadForm"')
if not action or not inputs:
- self.parseError("free download form")
+ self.error(_("Free download form not found"))
- self.logDebug('inputs.keys() = ' + str(inputs.keys()))
+ 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)
+ 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})
@@ -112,33 +108,36 @@ class UlozTo(SimpleHoster):
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))
+ 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)
+ 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.parseError("CAPTCHA form changed")
+ self.error(_("CAPTCHA form changed"))
self.multiDL = True
self.download("http://www.ulozto.net" + action, post=inputs, cookies=True, disposition=True)
+
def handlePremium(self):
self.download(self.pyfile.url + "?do=directDownload", disposition=True)
#parsed_url = self.findDownloadURL(premium=True)
#self.download(parsed_url, post={"download": "Download"})
+
def findDownloadURL(self, premium=False):
- msg = "%s link" % ("Premium" if premium else "Free")
+ msg = _("%s link" % ("Premium" if premium else "Free"))
m = re.search(self.PREMIUM_URL_PATTERN if premium else self.FREE_URL_PATTERN, self.html)
if m is None:
- self.parseError(msg)
+ self.error(msg)
parsed_url = "http://www.ulozto.net" + m.group(1)
self.logDebug("%s: %s" % (msg, parsed_url))
return parsed_url
+
def doCheckDownload(self):
check = self.checkDownload({
"wrong_captcha": re.compile(r'<ul class="error">\s*<li>Error rewriting the text.</li>'),
@@ -152,18 +151,18 @@ class UlozTo(SimpleHoster):
#self.delStorage("captcha_id")
#self.delStorage("captcha_text")
self.invalidCaptcha()
- self.retry(reason="Wrong captcha code")
+ self.retry(reason=_("Wrong captcha code"))
elif check == "offline":
self.offline()
elif check == "passwd":
- self.fail("Wrong password")
+ self.fail(_("Wrong password"))
elif check == "server_error":
- self.logError("Server error, try downloading later")
+ 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")
+ 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
index a77597324..0afa4e5a5 100644
--- a/module/plugins/hoster/UloziskoSk.py
+++ b/module/plugins/hoster/UloziskoSk.py
@@ -1,40 +1,29 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class UloziskoSk(SimpleHoster):
- __name__ = "UloziskoSk"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?ulozisko.sk/.*'
- __version__ = "0.23"
+ __name__ = "UloziskoSk"
+ __type__ = "hoster"
+ __version__ = "0.24"
+
+ __pattern__ = r'http://(?:www\.)?ulozisko\.sk/.+'
+
__description__ = """Ulozisko.sk hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'<div class="down1">(?P<N>[^<]+)</div>'
- FILE_SIZE_PATTERN = ur'Veğkosť súboru: <strong>(?P<S>[0-9.]+) (?P<U>[kKMG])i?B</strong><br />'
+
+ 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_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="" />'
+ 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 = "([^"]+)">'
@@ -49,27 +38,28 @@ class UloziskoSk(SimpleHoster):
else:
self.handleFree()
+
def handleFree(self):
m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.parseError('URL')
+ self.error(_("LINK_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.parseError('ID')
+ self.error(_("ID_PATTERN not found"))
id = m.group(1)
- self.logDebug('URL:' + parsed_url + ' ID:' + id)
+ self.logDebug("URL:" + parsed_url + ' ID:' + id)
m = re.search(self.CAPTCHA_PATTERN, self.html)
if m is None:
- self.parseError('CAPTCHA')
+ 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.logDebug("CAPTCHA_URL:" + captcha_url + ' CAPTCHA:' + captcha)
self.download(parsed_url, post={
"antispam": captcha,
diff --git a/module/plugins/hoster/UnibytesCom.py b/module/plugins/hoster/UnibytesCom.py
index 50e4c32d0..8c39cce82 100644
--- a/module/plugins/hoster/UnibytesCom.py
+++ b/module/plugins/hoster/UnibytesCom.py
@@ -1,49 +1,42 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
+import re
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
+from urlparse import urljoin
-import re
from pycurl import FOLLOWLOCATION
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class UnibytesCom(SimpleHoster):
- __name__ = "UnibytesCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?unibytes\.com/[a-zA-Z0-9-._ ]{11}B'
- __version__ = "0.1"
+ __name__ = "UnibytesCom"
+ __type__ = "hoster"
+ __version__ = "0.11"
+
+ __pattern__ = r'https?://(?:www\.)?unibytes\.com/[\w .-]{11}B'
+
__description__ = """UniBytes.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ HOSTER_DOMAIN = "unibytes.com"
- FILE_INFO_PATTERN = r'<span[^>]*?id="fileName"[^>]*>(?P<N>[^>]+)</span>\s*\((?P<S>\d.*?)\)'
+ INFO_PATTERN = r'<span[^>]*?id="fileName"[^>]*>(?P<N>[^>]+)</span>\s*\((?P<S>\d.*?)\)'
- HOSTER_NAME = "unibytes.com"
WAIT_PATTERN = r'Wait for <span id="slowRest">(\d+)</span> sec'
LINK_PATTERN = r'<a href="([^"]+)">Download</a>'
def handleFree(self):
- domain = "http://www." + self.HOSTER_NAME
+ domain = "http://www.%s/" % self.HOSTER_DOMAIN
action, post_data = self.parseHtmlForm('id="startForm"')
self.req.http.c.setopt(FOLLOWLOCATION, 0)
- for _ in xrange(8):
+ for _i in xrange(8):
self.logDebug(action, post_data)
- self.html = self.load(domain + action, post=post_data)
+ self.html = self.load(urljoin(domain, action), post=post_data)
m = re.search(r'location:\s*(\S+)', self.req.http.header, re.I)
if m:
@@ -70,11 +63,10 @@ class UnibytesCom(SimpleHoster):
m = re.search(self.WAIT_PATTERN, self.html)
self.wait(int(m.group(1)) if m else 60, False)
elif last_step in ("captcha", "last"):
- post_data['captcha'] = self.decryptCaptcha(domain + '/captcha.jpg')
+ post_data['captcha'] = self.decryptCaptcha(urljoin(domain, "/captcha.jpg"))
else:
- self.fail("No valid captcha code entered")
+ self.fail(_("No valid captcha code entered"))
- self.logDebug('Download link: ' + url)
self.req.http.c.setopt(FOLLOWLOCATION, 1)
self.download(url)
diff --git a/module/plugins/hoster/UnrestrictLi.py b/module/plugins/hoster/UnrestrictLi.py
index 7558dfcf6..6e16cace7 100644
--- a/module/plugins/hoster/UnrestrictLi.py
+++ b/module/plugins/hoster/UnrestrictLi.py
@@ -1,99 +1,88 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
+
from datetime import datetime, timedelta
-from module.plugins.Hoster import Hoster
from module.common.json_layer import json_loads
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
+from module.plugins.internal.SimpleHoster import secondsToMidnight
-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)
- midnight = midnight.replace(hour=0, minute=10, second=0, microsecond=0)
- return int((midnight - now).total_seconds())
-
+class UnrestrictLi(MultiHoster):
+ __name__ = "UnrestrictLi"
+ __type__ = "hoster"
+ __version__ = "0.19"
-class UnrestrictLi(Hoster):
- __name__ = "UnrestrictLi"
- __version__ = "0.12"
- __type__ = "hoster"
__pattern__ = r'https?://(?:[^/]*\.)?(unrestrict|unr)\.li'
+
__description__ = """Unrestrict.li hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
+
+ LOGIN_ACCOUNT = False
+
def setup(self):
- self.chunkLimit = 16
+ self.chunkLimit = 16
self.resumeDownload = True
- def process(self, pyfile):
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- elif not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "Unrestrict.li")
- self.fail("No Unrestrict.li account provided")
+
+ def handleFree(self):
+ for _i in xrange(5):
+ page = self.load('https://unrestrict.li/unrestrict.php',
+ post={'link': self.pyfile.url, 'domain': 'long'})
+ self.logDebug("JSON data: " + page)
+ if page != '':
+ break
else:
- self.logDebug("Old URL: %s" % pyfile.url)
- for _ in xrange(5):
- page = self.req.load('https://unrestrict.li/unrestrict.php',
- post={'link': pyfile.url, 'domain': 'long'})
- self.logDebug("JSON data: " + page)
- if page != '':
- 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 page or ("You are not allowed to "
- "download from this host" in page and self.premium):
- self.account.relogin(self.user)
- self.retry()
- elif "File offline" in page:
- self.offline()
- elif "You are not allowed to download from this host" in page:
- self.fail("You are not allowed to download from this host")
- elif "You have reached your daily limit for this host" in page:
- 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 page:
- self.logInfo("Hoster temporarily unavailable, waiting 1 minute and retry")
- self.retry(5, 60, "Hoster is temporarily unavailable")
- page = json_loads(page)
- new_url = page.keys()[0]
- self.api_data = page[new_url]
-
- if new_url != pyfile.url:
- self.logDebug("New URL: " + new_url)
+ 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 page or ("You are not allowed to "
+ "download from this host" in page and self.premium):
+ self.account.relogin(self.user)
+ self.retry()
+
+ elif "File offline" in page:
+ self.offline()
+
+ elif "You are not allowed to download from this host" in page:
+ self.fail(_("You are not allowed to download from this host"))
+
+ elif "You have reached your daily limit for this host" in page:
+ 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 page:
+ self.logInfo(_("Hoster temporarily unavailable, waiting 1 minute and retry"))
+ self.retry(5, 60, "Hoster is temporarily unavailable")
+
+ page = json_loads(page)
+ self.link = page.keys()[0]
+ self.api_data = page[self.link]
+
+ if self.link != self.pyfile.url:
+ self.logDebug("New URL: " + self.link)
if hasattr(self, 'api_data'):
self.setNameSize()
- self.download(new_url, disposition=True)
+
+ def checkFile(self):
+ super(UnrestrictLi, self).checkFile()
if self.getConfig("history"):
- self.load("https://unrestrict.li/history/&delete=all")
- self.logInfo("Download history deleted")
+ 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
new file mode 100644
index 000000000..7ae46ef38
--- /dev/null
+++ b/module/plugins/hoster/UpleaCom.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from urlparse import urljoin
+
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+
+class UpleaCom(XFSHoster):
+ __name__ = "UpleaCom"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __pattern__ = r'https?://(?:www\.)?uplea\.com/dl/\w{15}'
+
+ __description__ = """Uplea.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Redleon", None)]
+
+
+ HOSTER_DOMAIN = "uplea.com"
+
+ 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):
+ 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(int(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.wait(15)
+ self.download(m.group(1), disposition=True)
+
+
+getInfo = create_getInfo(UpleaCom)
diff --git a/module/plugins/hoster/UploadStationCom.py b/module/plugins/hoster/UploadStationCom.py
index b0229aba4..d987770fe 100644
--- a/module/plugins/hoster/UploadStationCom.py
+++ b/module/plugins/hoster/UploadStationCom.py
@@ -4,13 +4,16 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class UploadStationCom(DeadHoster):
- __name__ = "UploadStationCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?uploadstation\.com/file/(?P<id>[A-Za-z0-9]+)'
+ __name__ = "UploadStationCom"
+ __type__ = "hoster"
__version__ = "0.52"
+
+ __pattern__ = r'http://(?:www\.)?uploadstation\.com/file/(?P<ID>\w+)'
+
__description__ = """UploadStation.com hoster plugin"""
- __author_name__ = ("fragonib", "zoidberg")
- __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "zoidberg@mujmail.cz")
+ __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
new file mode 100644
index 000000000..6d8a032e9
--- /dev/null
+++ b/module/plugins/hoster/UploadableCh.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from time import sleep
+
+from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class UploadableCh(SimpleHoster):
+ __name__ = "UploadableCh"
+ __type__ = "hoster"
+ __version__ = "0.04"
+
+ __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")]
+
+
+ FILE_URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://www.uploadable.ch/file/\g<ID>')]
+
+ FILE_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 setup(self):
+ self.multiDL = False
+ self.chunkLimit = 1
+
+
+ def handleFree(self):
+ # Click the "free user" button and wait
+ a = self.load(self.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(self.pyfile.url, cookies=True, post={'checkDownload': "check"}, decode=True)
+ self.logDebug(b) #: Expected output: {"success":"showCaptcha"}
+
+ recaptcha = ReCaptcha(self)
+
+ challenge, response = 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(self.pyfile.url, cookies=True, post={'downloadLink': "show"}, decode=True)
+
+ self.wait(3)
+
+ # Download the file
+ self.download(self.pyfile.url, cookies=True, post={'download': "normal"}, disposition=True)
+
+
+ def checkFile(self):
+ super(UploadableCh, self).checkFile()
+
+ check = self.checkDownload({'wait_or_reconnect': re.compile("Please wait for"),
+ 'is_html' : re.compile("<head>")})
+
+ if check == "wait_or_reconnect":
+ self.logInfo("Downloadlimit reached, please wait or reconnect")
+ self.wait(60 * 60, True)
+ self.retry()
+
+ elif check == "is_html":
+ self.error("Downloaded file is an html file")
+
+
+getInfo = create_getInfo(UploadableCh)
diff --git a/module/plugins/hoster/UploadboxCom.py b/module/plugins/hoster/UploadboxCom.py
new file mode 100644
index 000000000..031c5f761
--- /dev/null
+++ b/module/plugins/hoster/UploadboxCom.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
index e41ae2e34..833468a80 100644
--- a/module/plugins/hoster/UploadedTo.py
+++ b/module/plugins/hoster/UploadedTo.py
@@ -1,18 +1,19 @@
# -*- coding: utf-8 -*-
-
-# Test links (random.bin):
+#
+# Test links:
# http://ul.to/044yug9o
# http://ul.to/gzfhd0xs
import re
-from time import sleep
-from module.utils import html_unescape, parseFileSize
+from time import sleep
-from module.plugins.Hoster import Hoster
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.utils import html_unescape, parseFileSize
+
key = "bGhGMkllZXByd2VEZnU5Y2NXbHhYVlZ5cEE1bkEzRUw=".decode('base64')
@@ -30,10 +31,10 @@ def getAPIData(urls):
for i, url in enumerate(urls):
id = getID(url)
- post["id_%s" % i] = id
+ post['id_%s' % i] = id
idMap[id] = url
- for _ in xrange(5):
+ for _i in xrange(5):
api = unicode(getURL("http://uploaded.net/api/filemultiple", post=post, decode=False), 'iso-8859-1')
if api != "can't find request":
break
@@ -63,7 +64,7 @@ def parseFileInfo(self, url='', html=''):
# File offline
status = 1
else:
- m = re.search(self.FILE_INFO_PATTERN, html)
+ m = re.search(self.INFO_PATTERN, html)
if m:
name, fileid = html_unescape(m.group('N')), m.group('ID')
size = parseFileSize(m.group('S'))
@@ -91,26 +92,34 @@ def getInfo(urls):
class UploadedTo(Hoster):
- __name__ = "UploadedTo"
- __type__ = "hoster"
+ __name__ = "UploadedTo"
+ __type__ = "hoster"
+ __version__ = "0.75"
+
__pattern__ = r'https?://(?:www\.)?(uploaded\.(to|net)|ul\.to)(/file/|/?\?id=|.*?&id=|/)(?P<ID>\w+)'
- __version__ = "0.73"
+
__description__ = """Uploaded.net hoster plugin"""
- __author_name__ = ("spoob", "mkaay", "zoidberg", "netpok", "stickell")
- __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de", "zoidberg@mujmail.cz",
- "netpok@gmail.com", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org"),
+ ("mkaay", "mkaay@mkaay.de"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("netpok", "netpok@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
+
- FILE_INFO_PATTERN = r'<a href="file/(?P<ID>\w+)" id="filename">(?P<N>[^<]+)</a> &nbsp;\s*<small[^>]*>(?P<S>[^<]+)</small>'
+ INFO_PATTERN = r'<a href="file/(?P<ID>\w+)" id="filename">(?P<N>[^<]+)</a> &nbsp;\s*<small[^>]*>(?P<S>[^<]+)</small>'
OFFLINE_PATTERN = r'<small class="cL">Error: 404</small>'
DL_LIMIT_PATTERN = r'You have reached the max. number of possible free downloads for this hour'
+
def setup(self):
- self.multiDL = self.resumeDownload = self.premium
+ self.multiDL = self.resumeDownload = self.premium
self.chunkLimit = 1 # critical problems with more chunks
self.fileID = getID(self.pyfile.url)
self.pyfile.url = "http://uploaded.net/file/%s" % self.fileID
+
def process(self, pyfile):
self.load("http://uploaded.net/language/en", just_header=True)
@@ -119,7 +128,7 @@ class UploadedTo(Hoster):
# TODO: fallback to parse from site, because api sometimes delivers wrong status codes
if not api:
- self.logWarning("No response for API call")
+ self.logWarning(_("No response for API call"))
self.html = unicode(self.load(pyfile.url, decode=False), 'iso-8859-1')
name, size, status, self.fileID = parseFileInfo(self)
@@ -129,7 +138,8 @@ class UploadedTo(Hoster):
elif status == 2:
pyfile.name, pyfile.size = name, size
else:
- self.fail('Parse error - file info')
+ self.error(_("file info"))
+
elif api == 'Access denied':
self.fail(_("API key invalid"))
@@ -150,83 +160,82 @@ class UploadedTo(Hoster):
else:
self.handleFree()
+
def handlePremium(self):
info = self.account.getAccountInfo(self.user, True)
self.logDebug("%(name)s: Use Premium Account (%(left)sGB left)" % {"name": self.__name__,
"left": info['trafficleft'] / 1024 / 1024})
if int(self.data[1]) / 1024 > info['trafficleft']:
- self.logInfo(_("%s: Not enough traffic left" % self.__name__))
+ self.logInfo(_("Not enough traffic left"))
self.account.empty(self.user)
self.resetAccount()
self.fail(_("Traffic exceeded"))
header = self.load("http://uploaded.net/file/%s" % self.fileID, just_header=True)
- if "location" in header:
+ if 'location' in header:
#Direct download
- print "Direct Download: " + header['location']
+ self.logDebug("Direct download link detected")
self.download(header['location'])
else:
#Indirect download
self.html = self.load("http://uploaded.net/file/%s" % self.fileID)
m = re.search(r'<div class="tfree".*\s*<form method="post" action="(.*?)"', self.html)
if m is None:
- self.fail("Download URL not m. Try to enable direct downloads.")
+ self.fail(_("Download URL not m. Try to enable direct downloads"))
url = m.group(1)
- print "Premium URL: " + url
self.download(url, post={})
+
def handleFree(self):
self.html = self.load(self.pyfile.url, decode=True)
if 'var free_enabled = false;' in self.html:
- self.logError("Free-download capacities exhausted.")
- self.retry(max_tries=24, wait_time=5 * 60)
+ self.logError(_("Free-download capacities exhausted"))
+ self.retry(24, 5 * 60)
m = re.search(r"Current waiting period: <span>(\d+)</span> seconds", self.html)
if m is None:
- self.fail("File not downloadable for free users")
+ self.fail(_("File not downloadable for free users"))
self.setWait(int(m.group(1)))
- js = self.load("http://uploaded.net/js/download.js", decode=True)
-
- challengeId = re.search(r'Recaptcha\.create\("([^"]+)', js)
+ self.html = self.load("http://uploaded.net/js/download.js", decode=True)
url = "http://uploaded.net/io/ticket/captcha/%s" % self.fileID
downloadURL = ""
- for _ in xrange(5):
- re_captcha = ReCaptcha(self)
- challenge, result = re_captcha.challenge(challengeId.group(1))
- options = {"recaptcha_challenge_field": challenge, "recaptcha_response_field": result}
+ recaptcha = ReCaptcha(self)
+
+ for _i in xrange(5):
+ challenge, response = recaptcha.challenge()
+ options = {"recaptcha_challenge_field": challenge, "recaptcha_response_field": response}
self.wait()
result = self.load(url, post=options)
- self.logDebug("result: %s" % result)
+ self.logDebug("Result: %s" % result)
if "limit-size" in result:
- self.fail("File too big for free download")
+ self.fail(_("File too big for free download"))
elif "limit-slot" in result: # Temporary restriction so just wait a bit
self.setWait(30 * 60, True)
self.wait()
self.retry()
elif "limit-parallel" in result:
- self.fail("Cannot download in parallel")
- elif self.DL_LIMIT_PATTERN in result: # limit-dl
+ self.fail(_("Cannot download in parallel"))
+ elif "limit-dl" in result or self.DL_LIMIT_PATTERN in result: # limit-dl
self.setWait(3 * 60 * 60, True)
self.wait()
self.retry()
elif '"err":"captcha"' in result:
- self.logError("ul.net captcha is disabled")
self.invalidCaptcha()
elif "type:'download'" in result:
self.correctCaptcha()
downloadURL = re.search("url:'([^']+)", result).group(1)
break
else:
- self.fail("Unknown error '%s'" % result)
+ self.error(_("Unknown error: %s") % result)
if not downloadURL:
- self.fail("No Download url retrieved/all captcha attempts failed")
+ self.fail(_("No Download url retrieved/all captcha attempts failed"))
self.download(downloadURL, disposition=True)
check = self.checkDownload({"limit-dl": self.DL_LIMIT_PATTERN})
diff --git a/module/plugins/hoster/UploadhereCom.py b/module/plugins/hoster/UploadhereCom.py
new file mode 100644
index 000000000..8da30be46
--- /dev/null
+++ b/module/plugins/hoster/UploadhereCom.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
index 05f8e1199..189079017 100644
--- a/module/plugins/hoster/UploadheroCom.py
+++ b/module/plugins/hoster/UploadheroCom.py
@@ -1,47 +1,37 @@
# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-# Test link (random.bin):
+#
+# Test links:
# http://uploadhero.co/dl/wQBRAVSM
import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class UploadheroCom(SimpleHoster):
- __name__ = "UploadheroCom"
- __type__ = "hoster"
+ __name__ = "UploadheroCom"
+ __type__ = "hoster"
+ __version__ = "0.16"
+
__pattern__ = r'http://(?:www\.)?uploadhero\.com?/dl/\w+'
- __version__ = "0.15"
+
__description__ = """UploadHero.co plugin"""
- __author_name__ = ("mcmyst", "zoidberg")
- __author_mail__ = ("mcmyst@hotmail.fr", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("mcmyst", "mcmyst@hotmail.fr"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_NAME_PATTERN = r'<div class="nom_de_fichier">(?P<N>.*?)</div>'
- FILE_SIZE_PATTERN = r'Taille du fichier : </span><strong>(?P<S>.*?)</strong>'
+ 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.'
- SH_COOKIES = [(".uploadhero.co", "lang", "en")]
+ COOKIES = [("uploadhero.co", "lang", "en")]
- IP_BLOCKED_PATTERN = r'href="(/lightbox_block_download.php\?min=.*?)"'
+ 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\?[a-z0-9]+)"'
- FREE_URL_PATTERN = r'var magicomfg = \'<a href="(http://[^<>"]*?)"|"(http://storage\d+\.uploadhero\.co/\?d=[A-Za-z0-9]+/[^<>"/]+)"'
+ CAPTCHA_PATTERN = r'"(/captchadl\.php\?\w+)"'
+ FREE_URL_PATTERN = r'var magicomfg = \'<a href="(http://[^<>"]*?)"|"(http://storage\d+\.uploadhero\.co/\?d=\w+/[^<>"/]+)"'
PREMIUM_URL_PATTERN = r'<a href="([^"]+)" id="downloadnow"'
@@ -50,10 +40,10 @@ class UploadheroCom(SimpleHoster):
m = re.search(self.CAPTCHA_PATTERN, self.html)
if m is None:
- self.parseError("Captcha URL")
+ self.error(_("CAPTCHA_PATTERN not found"))
captcha_url = "http://uploadhero.co" + m.group(1)
- for _ in xrange(5):
+ for _i in xrange(5):
captcha = self.decryptCaptcha(captcha_url)
self.html = self.load(self.pyfile.url, get={"code": captcha})
m = re.search(self.FREE_URL_PATTERN, self.html)
@@ -64,17 +54,17 @@ class UploadheroCom(SimpleHoster):
else:
self.invalidCaptcha()
else:
- self.fail("No valid captcha code entered")
+ self.fail(_("No valid captcha code entered"))
self.download(download_url)
+
def handlePremium(self):
self.logDebug("%s: Use Premium Account" % self.__name__)
- self.html = self.load(self.pyfile.url)
link = re.search(self.PREMIUM_URL_PATTERN, self.html).group(1)
- self.logDebug("Downloading link : '%s'" % link)
self.download(link)
+
def checkErrors(self):
m = re.search(self.IP_BLOCKED_PATTERN, self.html)
if m:
@@ -85,5 +75,7 @@ class UploadheroCom(SimpleHoster):
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
index 1c6583c12..b163f2252 100644
--- a/module/plugins/hoster/UploadingCom.py
+++ b/module/plugins/hoster/UploadingCom.py
@@ -1,61 +1,53 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from pycurl import HTTPHEADER
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp
from module.common.json_layer import json_loads
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp
class UploadingCom(SimpleHoster):
- __name__ = "UploadingCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?uploading\.com/files/(?:get/)?(?P<ID>[\w\d]+)'
- __version__ = "0.35"
+ __name__ = "UploadingCom"
+ __type__ = "hoster"
+ __version__ = "0.39"
+
+ __pattern__ = r'http://(?:www\.)?uploading\.com/files/(?:get/)?(?P<ID>\w+)'
+
__description__ = """Uploading.com hoster plugin"""
- __author_name__ = ("jeix", "mkaay", "zoidberg")
- __author_mail__ = ("jeix@hasnomail.de", "mkaay@mkaay.de", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de"),
+ ("mkaay", "mkaay@mkaay.de"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'id="file_title">(?P<N>.+)</'
- FILE_SIZE_PATTERN = r'size tip_container">(?P<S>[\d.]+) (?P<U>\w+)<'
- OFFLINE_PATTERN = r'Page not found!'
- def process(self, pyfile):
- # set lang to english
- self.req.cj.setCookie(".uploading.com", "lang", "1")
- self.req.cj.setCookie(".uploading.com", "language", "1")
- self.req.cj.setCookie(".uploading.com", "setlang", "en")
- self.req.cj.setCookie(".uploading.com", "_lang", "en")
+ 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.file_info = self.getFileInfo()
+ self.getFileInfo()
if self.premium:
self.handlePremium()
else:
self.handleFree()
+
def handlePremium(self):
postData = {'action': 'get_link',
- 'code': self.file_info['ID'],
+ 'code': self.info['pattern']['ID'],
'pass': 'undefined'}
self.html = self.load('http://uploading.com/files/get/?JsHttpRequest=%d-xml' % timestamp(), post=postData)
@@ -64,46 +56,48 @@ class UploadingCom(SimpleHoster):
url = url.group(1).replace("\\/", "/")
self.download(url)
- raise Exception("Plugin defect.")
+ raise Exception("Plugin defect")
+
def handleFree(self):
m = re.search('<h2>((Daily )?Download Limit)</h2>', self.html)
if m:
self.pyfile.error = m.group(1)
self.logWarning(self.pyfile.error)
- self.retry(max_tries=6, wait_time=6 * 60 * 60 if m.group(2) else 15 * 60, reason=self.pyfile.error)
+ self.retry(6, (6 * 60 if m.group(2) else 15) * 60, self.pyfile.error)
ajax_url = "http://uploading.com/files/get/?ajax"
self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"])
self.req.http.lastURL = self.pyfile.url
- response = json_loads(self.load(ajax_url, post={'action': 'second_page', 'code': self.file_info['ID']}))
- if 'answer' in response and 'wait_time' in response['answer']:
- wait_time = int(response['answer']['wait_time'])
- self.logInfo("%s: Waiting %d seconds." % (self.__name__, wait_time))
+ 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.parseError("AJAX/WAIT")
+ self.error(_("No AJAX/WAIT"))
+
+ res = json_loads(self.load(ajax_url, post={'action': 'get_link', 'code': self.info['pattern']['ID'], 'pass': 'false'}))
- response = json_loads(
- self.load(ajax_url, post={'action': 'get_link', 'code': self.file_info['ID'], 'pass': 'false'}))
- if 'answer' in response and 'link' in response['answer']:
- url = response['answer']['link']
+ if 'answer' in res and 'link' in res['answer']:
+ url = res['answer']['link']
else:
- self.parseError("AJAX/URL")
+ 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.parseError("URL")
+ self.error(_("No URL"))
self.download(url)
check = self.checkDownload({"html": re.compile("\A<!DOCTYPE html PUBLIC")})
if check == "html":
- self.logWarning("Redirected to a HTML page, wait 10 minutes and retry")
+ self.logWarning(_("Redirected to a HTML page, wait 10 minutes and retry"))
self.wait(10 * 60, True)
diff --git a/module/plugins/hoster/UploadkingCom.py b/module/plugins/hoster/UploadkingCom.py
new file mode 100644
index 000000000..743e700eb
--- /dev/null
+++ b/module/plugins/hoster/UploadkingCom.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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
index 99aa25b48..25c424f1f 100644
--- a/module/plugins/hoster/UpstoreNet.py
+++ b/module/plugins/hoster/UpstoreNet.py
@@ -1,20 +1,24 @@
# -*- coding: utf-8 -*-
+
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class UpstoreNet(SimpleHoster):
- __name__ = "UpstoreNet"
- __type__ = "hoster"
+ __name__ = "UpstoreNet"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
__pattern__ = r'https?://(?:www\.)?upstore\.net/'
- __version__ = "0.02"
+
__description__ = """Upstore.Net File Download Hoster"""
- __author_name__ = "igel"
- __author_mail__ = "igelkun@myopera.com"
+ __license__ = "GPLv3"
+ __authors__ = [("igel", "igelkun@myopera.com")]
+
- FILE_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+)'
+ 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+)'
@@ -26,9 +30,9 @@ class UpstoreNet(SimpleHoster):
# STAGE 1: get link to continue
m = re.search(self.CHASH_PATTERN, self.html)
if m is None:
- self.parseError("could not detect hash")
+ self.error(_("CHASH_PATTERN not found"))
chash = m.group(1)
- self.logDebug("read hash " + chash)
+ self.logDebug("Read hash " + chash)
# continue to stage2
post_data = {'hash': chash, 'free': 'Slow download'}
self.html = self.load(self.pyfile.url, post=post_data, decode=True)
@@ -36,36 +40,33 @@ class UpstoreNet(SimpleHoster):
# STAGE 2: solv captcha and wait
# first get the infos we need: recaptcha key and wait time
recaptcha = ReCaptcha(self)
- if not recaptcha.detect_key(self.html):
- self.parseError("could not find recaptcha pattern")
- self.logDebug("using captcha key " + recaptcha.recaptcha_key)
+
# try the captcha 5 times
for i in xrange(5):
m = re.search(self.WAIT_PATTERN, self.html)
if m is None:
- self.parseError("could not find wait pattern")
- wait_time = m.group(1)
+ self.error(_("Wait pattern not found"))
+ wait_time = int(m.group(1))
# then, do the waiting
self.wait(wait_time)
# then, handle the captcha
- challenge, code = recaptcha.challenge()
- post_data['recaptcha_challenge_field'] = challenge
- post_data['recaptcha_response_field'] = code
+ challenge, response = recaptcha.challenge()
+ post_data.update({'recaptcha_challenge_field': challenge,
+ 'recaptcha_response_field' : response})
self.html = self.load(self.pyfile.url, post=post_data, decode=True)
# STAGE 3: get direct link
- m = re.search(self.LINK_PATTERN, self.html, re.DOTALL)
+ m = re.search(self.LINK_PATTERN, self.html, re.S)
if m:
break
if m is None:
- self.parseError("could not detect direct link")
+ self.error(_("Download link not found"))
direct = m.group(1)
- self.logDebug('found direct link: ' + direct)
self.download(direct, disposition=True)
diff --git a/module/plugins/hoster/UptoboxCom.py b/module/plugins/hoster/UptoboxCom.py
index 20a2d675a..21d781f55 100644
--- a/module/plugins/hoster/UptoboxCom.py
+++ b/module/plugins/hoster/UptoboxCom.py
@@ -1,79 +1,34 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-import re
-from urllib import unquote
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-from module.plugins.internal.CaptchaService import ReCaptcha, SolveMedia
-from module.utils import html_unescape
+class UptoboxCom(XFSHoster):
+ __name__ = "UptoboxCom"
+ __type__ = "hoster"
+ __version__ = "0.16"
+
+ __pattern__ = r'https?://(?:www\.)?uptobox\.com/\w{12}'
-class UptoboxCom(XFileSharingPro):
- __name__ = "UptoboxCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?uptobox\.com/\w+'
- __version__ = "0.09"
__description__ = """Uptobox.com hoster plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- HOSTER_NAME = "uptobox.com"
- FILE_INFO_PATTERN = r'"para_title">(?P<N>.+) \((?P<S>[\d\.]+) (?P<U>\w+)\)'
- OFFLINE_PATTERN = r'>(File not found|Access Denied|404 Not Found)'
- TEMP_OFFLINE_PATTERN = r'>This server is in maintenance mode'
+ HOSTER_DOMAIN = "uptobox.com"
- WAIT_PATTERN = r'>(\d+)</span> seconds<'
+ 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/.*?)"'
- def handleCaptcha(self, inputs):
- m = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if m:
- captcha_key = m.group(1)
- captcha = SolveMedia(self)
- inputs['adcopy_challenge'], inputs['adcopy_response'] = captcha.challenge(captcha_key)
- return 4
- else:
- m = re.search(self.CAPTCHA_URL_PATTERN, self.html)
- if m:
- captcha_url = m.group(1)
- inputs['code'] = self.decryptCaptcha(captcha_url)
- return 2
- else:
- m = re.search(self.CAPTCHA_DIV_PATTERN, self.html, re.DOTALL)
- if m:
- captcha_div = m.group(1)
- self.logDebug(captcha_div)
- numerals = re.findall(r'<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>',
- html_unescape(captcha_div))
- inputs['code'] = "".join([a[1] for a in sorted(numerals, key=lambda num: int(num[0]))])
- self.logDebug("CAPTCHA", inputs['code'], numerals)
- return 3
- else:
- m = re.search(self.RECAPTCHA_URL_PATTERN, self.html)
- if m:
- recaptcha_key = unquote(m.group(1))
- self.logDebug("RECAPTCHA KEY: %s" % recaptcha_key)
- recaptcha = ReCaptcha(self)
- inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(
- recaptcha_key)
- return 1
- return 0
+ 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/VeehdCom.py b/module/plugins/hoster/VeehdCom.py
index 15cff646f..d894dab24 100644
--- a/module/plugins/hoster/VeehdCom.py
+++ b/module/plugins/hoster/VeehdCom.py
@@ -1,27 +1,29 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.Hoster import Hoster
class VeehdCom(Hoster):
- __name__ = "VeehdCom"
- __type__ = "hoster"
+ __name__ = "VeehdCom"
+ __type__ = "hoster"
+ __version__ = "0.23"
+
__pattern__ = r'http://veehd\.com/video/\d+_\S+'
__config__ = [("filename_spaces", "bool", "Allow spaces in filename", False),
("replacement_char", "str", "Filename replacement character", "_")]
- __version__ = "0.23"
+
__description__ = """Veehd.com hoster plugin"""
- __author_name__ = "cat"
- __author_mail__ = "cat@pyload"
+ __license__ = "GPLv3"
+ __authors__ = [("cat", "cat@pyload")]
- def _debug(self, msg):
- self.logDebug('[%s] %s' % (self.__name__, msg))
def setup(self):
self.multiDL = True
self.req.canContinue = True
+
def process(self, pyfile):
self.download_html()
if not self.file_exists():
@@ -30,11 +32,13 @@ class VeehdCom(Hoster):
pyfile.name = self.get_file_name()
self.download(self.get_file_url())
+
def download_html(self):
url = self.pyfile.url
- self._debug("Requesting page: %s" % (repr(url),))
+ self.logDebug("Requesting page: %s" % url)
self.html = self.load(url)
+
def file_exists(self):
if not self.html:
self.download_html()
@@ -43,24 +47,26 @@ class VeehdCom(Hoster):
return False
return True
+
def get_file_name(self):
if not self.html:
self.download_html()
m = re.search(r'<title[^>]*>([^<]+) on Veehd</title>', self.html)
if m is None:
- self.fail("video title not found")
+ self.error(_("Video title not found"))
name = m.group(1)
# replace unwanted characters in filename
if self.getConfig('filename_spaces'):
- pattern = '[^0-9A-Za-z\.\ ]+'
+ pattern = '[^\w ]+'
else:
- pattern = '[^0-9A-Za-z\.]+'
+ pattern = '[^\w.]+'
return re.sub(pattern, self.getConfig('replacement_char'), name) + '.avi'
+
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
@@ -70,6 +76,6 @@ class VeehdCom(Hoster):
m = re.search(r'<embed type="video/divx" src="(http://([^/]*\.)?veehd\.com/dl/[^"]+)"',
self.html)
if m is None:
- self.fail("embedded video url not found")
+ self.error(_("Embedded video url not found"))
return m.group(1)
diff --git a/module/plugins/hoster/VeohCom.py b/module/plugins/hoster/VeohCom.py
index 9dbc9b8ad..6dbac397b 100644
--- a/module/plugins/hoster/VeohCom.py
+++ b/module/plugins/hoster/VeohCom.py
@@ -1,18 +1,4 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-############################################################################
import re
@@ -20,25 +6,31 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class VeohCom(SimpleHoster):
- __name__ = "VeohCom"
- __type__ = "hoster"
+ __name__ = "VeohCom"
+ __type__ = "hoster"
+ __version__ = "0.21"
+
__pattern__ = r'http://(?:www\.)?veoh\.com/(tv/)?(watch|videos)/(?P<ID>v\w+)'
- __version__ = "0.2"
__config__ = [("quality", "Low;High;Auto", "Quality", "Auto")]
+
__description__ = """Veoh.com hoster plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
- FILE_NAME_PATTERN = r'<meta name="title" content="(?P<N>.*?)"'
+ NAME_PATTERN = r'<meta name="title" content="(?P<N>.*?)"'
OFFLINE_PATTERN = r'>Sorry, we couldn\'t find the video you were looking for'
- FILE_URL_REPLACEMENTS = [(__pattern__, r'http://www.veoh.com/watch/\g<ID>')]
+ URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://www.veoh.com/watch/\g<ID>')]
+
+ COOKIES = [("veoh.com", "lassieLocale", "en")]
- SH_COOKIES = [(".veoh.com", "lassieLocale", "en")]
def setup(self):
- self.resumeDownload = self.multiDL = True
- self.chunkLimit = -1
+ self.resumeDownload = True
+ self.multiDL = True
+ self.chunkLimit = -1
+
def handleFree(self):
quality = self.getConfig("quality")
@@ -50,13 +42,12 @@ class VeohCom(SimpleHoster):
if m:
self.pyfile.name += ".mp4"
link = m.group(1).replace("\\", "")
- self.logDebug("Download link: " + link)
self.download(link)
return
else:
- self.logInfo("No %s quality video found" % q.upper())
+ self.logInfo(_("No %s quality video found") % q.upper())
else:
- self.fail("No video found!")
+ self.fail(_("No video found!"))
getInfo = create_getInfo(VeohCom)
diff --git a/module/plugins/hoster/VidPlayNet.py b/module/plugins/hoster/VidPlayNet.py
index 3407f4349..76af05edd 100644
--- a/module/plugins/hoster/VidPlayNet.py
+++ b/module/plugins/hoster/VidPlayNet.py
@@ -1,25 +1,26 @@
# -*- coding: utf-8 -*-
-
+#
# Test links:
# BigBuckBunny_320x180.mp4 - 61.7 Mb - http://vidplay.net/38lkev0h3jv0
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+class VidPlayNet(XFSHoster):
+ __name__ = "VidPlayNet"
+ __type__ = "hoster"
+ __version__ = "0.04"
-class VidPlayNet(XFileSharingPro):
- __name__ = "VidPlayNet"
- __type__ = "hoster"
__pattern__ = r'https?://(?:www\.)?vidplay\.net/\w{12}'
- __version__ = "0.01"
+
__description__ = """VidPlay.net hoster plugin"""
- __author_name__ = "t4skforce"
- __author_mail__ = "t4skforce1337[AT]gmail[DOT]com"
+ __license__ = "GPLv3"
+ __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")]
+
- HOSTER_NAME = "vidplay.net"
+ HOSTER_DOMAIN = "vidplay.net"
- OFFLINE_PATTERN = r'<b>File Not Found</b><br>\s*<br>'
- FILE_NAME_PATTERN = r'<b>Password:</b></div>\s*<h[1-6]>(?P<N>[^<]+)</h[1-6]>'
- LINK_PATTERN = r'(http://([^/]*?%s|\d+\.\d+\.\d+\.\d+)(:\d+)?(/d/|(?:/files)?/\d+/\w+/)[^"\'<&]+)' % HOSTER_NAME
+ 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
index 2c7f4b9c3..0e42c1674 100644
--- a/module/plugins/hoster/VimeoCom.py
+++ b/module/plugins/hoster/VimeoCom.py
@@ -1,18 +1,4 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-############################################################################
import re
@@ -20,36 +6,43 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class VimeoCom(SimpleHoster):
- __name__ = "VimeoCom"
- __type__ = "hoster"
+ __name__ = "VimeoCom"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
__pattern__ = r'https?://(?:www\.)?(player\.)?vimeo\.com/(video/)?(?P<ID>\d+)'
- __version__ = "0.01"
__config__ = [("quality", "Lowest;Mobile;SD;HD;Highest", "Quality", "Highest"),
("original", "bool", "Try to download the original file first", True)]
+
__description__ = """Vimeo.com hoster plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
- FILE_NAME_PATTERN = r'<title>(?P<N>.+) on Vimeo<'
- OFFLINE_PATTERN = r'class="exception_header"'
+ 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.<'
- FILE_URL_REPLACEMENTS = [(__pattern__, r'https://www.vimeo.com/\g<ID>')]
+ URL_REPLACEMENTS = [(__pattern__ + ".*", r'https://www.vimeo.com/\g<ID>')]
- SH_COOKIES = [(".vimeo.com", "language", "en")]
+ COOKIES = [("vimeo.com", "language", "en")]
def setup(self):
- self.resumeDownload = self.multiDL = True
- self.chunkLimit = -1
+ self.resumeDownload = True
+ self.multiDL = True
+ self.chunkLimit = -1
+
def handleFree(self):
+ password = self.getPassword()
+
if self.js and 'class="btn iconify_down_b"' in self.html:
- html = self.js.eval(self.load(self.pyfile.url, get={'action': "download"}, decode=True))
+ html = self.js.eval(self.load(self.pyfile.url, get={'action': "download", 'password': password}, decode=True))
pattern = r'href="(?P<URL>http://vimeo\.com.+?)".*?\>(?P<QL>.+?) '
else:
- id = re.match(self.__pattern__, self.pyfile.url).group("ID")
- html = self.load("https://player.vimeo.com/video/" + id)
+ id = re.match(self.__pattern__, self.pyfile.url).group('ID')
+ html = self.load("https://player.vimeo.com/video/" + 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)])
@@ -59,7 +52,7 @@ class VimeoCom(SimpleHoster):
self.download(link[q])
return
else:
- self.logInfo("Original file not downloadable")
+ self.logInfo(_("Original file not downloadable"))
quality = self.getConfig("quality")
if quality == "Highest":
@@ -74,9 +67,9 @@ class VimeoCom(SimpleHoster):
self.download(link[q])
return
else:
- self.logInfo("No %s quality video found" % q.upper())
+ self.logInfo(_("No %s quality video found") % q.upper())
else:
- self.fail("No video found!")
+ self.fail(_("No video found!"))
getInfo = create_getInfo(VimeoCom)
diff --git a/module/plugins/hoster/Vipleech4uCom.py b/module/plugins/hoster/Vipleech4uCom.py
index d4ccf997a..340a3feaa 100644
--- a/module/plugins/hoster/Vipleech4uCom.py
+++ b/module/plugins/hoster/Vipleech4uCom.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class Vipleech4uCom(DeadHoster):
- __name__ = "Vipleech4uCom"
- __version__ = "0.2"
- __type__ = "hoster"
+ __name__ = "Vipleech4uCom"
+ __type__ = "hoster"
+ __version__ = "0.20"
+
__pattern__ = r'http://(?:www\.)?vipleech4u\.com/manager\.php'
+
__description__ = """Vipleech4u.com hoster plugin"""
- __author_name__ = "Kagenoshin"
- __author_mail__ = "kagenoshin@gmx.ch"
+ __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
index 73c5b6bc7..c83d5c03e 100644
--- a/module/plugins/hoster/WarserverCz.py
+++ b/module/plugins/hoster/WarserverCz.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class WarserverCz(DeadHoster):
- __name__ = "WarserverCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?warserver\.cz/stahnout/\d+'
+ __name__ = "WarserverCz"
+ __type__ = "hoster"
__version__ = "0.13"
+
+ __pattern__ = r'http://(?:www\.)?warserver\.cz/stahnout/\d+'
+
__description__ = """Warserver.cz hoster plugin"""
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __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
index 64691ad69..a08341ff3 100644
--- a/module/plugins/hoster/WebshareCz.py
+++ b/module/plugins/hoster/WebshareCz.py
@@ -1,71 +1,64 @@
# -*- coding: utf-8 -*-
-############################################################################
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU Affero General Public License as #
-# published by the Free Software Foundation, either version 3 of the #
-# License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU Affero General Public License for more details. #
-# #
-# You should have received a copy of the GNU Affero General Public License #
-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
-############################################################################
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster
-from module.network.RequestFactory import getRequest
+from module.network.RequestFactory import getURL
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-def getInfo(urls):
- h = getRequest()
- for url in urls:
- h.load(url)
- fid = re.search(WebshareCz.__pattern__, url).group('ID')
- api_data = h.load('https://webshare.cz/api/file_info/', post={'ident': fid})
- if 'File not found' in api_data:
- file_info = (url, 0, 1, url)
- else:
- name = re.search('<name>(.+)</name>', api_data).group(1)
- size = re.search('<size>(.+)</size>', api_data).group(1)
- file_info = (name, size, 2, url)
- yield file_info
+class WebshareCz(SimpleHoster):
+ __name__ = "WebshareCz"
+ __type__ = "hoster"
+ __version__ = "0.14"
+ __pattern__ = r'https?://(?:www\.)?webshare\.cz/(?:#/)?file/(?P<ID>\w+)'
-class WebshareCz(SimpleHoster):
- __name__ = "WebshareCz"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?webshare.cz/(?:#/)?file/(?P<ID>\w+)'
- __version__ = "0.13"
__description__ = """WebShare.cz hoster plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it"),
+ ("rush", "radek.senfeld@gmail.com")]
+
+
+ @classmethod
+ def getInfo(cls, url="", html=""):
+ info = super(WebshareCz, self).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):
- api_data = self.load('https://webshare.cz/api/file_link/', post={'ident': self.fid})
+ fid = re.match(self.__pattern__, self.pyfile.url).group('ID')
+ 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': fid, 'wst': wst},
+ decode=True)
+
self.logDebug("API data: " + api_data)
+
m = re.search('<link>(.+)</link>', api_data)
if m is None:
- self.parseError('Unable to detect direct link')
- direct = m.group(1)
- self.logDebug("Direct link: " + direct)
- self.download(direct, disposition=True)
+ self.error(_("Unable to detect direct link"))
- def getFileInfo(self):
- self.logDebug("URL: %s" % self.pyfile.url)
+ self.link = m.group(1)
- self.fid = re.match(self.__pattern__, self.pyfile.url).group('ID')
- self.load(self.pyfile.url)
- api_data = self.load('https://webshare.cz/api/file_info/', post={'ident': self.fid})
+ def handlePremium(self):
+ return self.handleFree()
- if 'File not found' in api_data:
- self.offline()
- else:
- self.pyfile.name = re.search('<name>(.+)</name>', api_data).group(1)
- self.pyfile.size = re.search('<size>(.+)</size>', api_data).group(1)
- self.logDebug("FILE NAME: %s FILE SIZE: %s" % (self.pyfile.name, self.pyfile.size))
+getInfo = create_getInfo(WebshareCz)
diff --git a/module/plugins/hoster/WrzucTo.py b/module/plugins/hoster/WrzucTo.py
index 3bcd8dccc..8e9653307 100644
--- a/module/plugins/hoster/WrzucTo.py
+++ b/module/plugins/hoster/WrzucTo.py
@@ -1,48 +1,38 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
+
from pycurl import HTTPHEADER
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class WrzucTo(SimpleHoster):
- __name__ = "WrzucTo"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?wrzuc\.to/([a-zA-Z0-9]+(\.wt|\.html)|(\w+/?linki/[a-zA-Z0-9]+))'
- __version__ = "0.01"
+ __name__ = "WrzucTo"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?wrzuc\.to/(\w+(\.wt|\.html)|(\w+/?linki/\w+))'
+
__description__ = """Wrzuc.to hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- FILE_NAME_PATTERN = r'id="file_info">\s*<strong>(?P<N>.*?)</strong>'
- FILE_SIZE_PATTERN = r'class="info">\s*<tr>\s*<td>(?P<S>.*?)</td>'
- SH_COOKIES = [(".wrzuc.to", "language", "en")]
+ 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):
data = dict(re.findall(r'(md5|file): "(.*?)"', self.html))
if len(data) != 2:
- self.parseError('File ID')
+ self.error(_("No file ID"))
self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"])
self.req.http.lastURL = self.pyfile.url
@@ -53,10 +43,9 @@ class WrzucTo(SimpleHoster):
data.update(re.findall(r'"(download_link|server_id)":"(.*?)"', self.html))
if len(data) != 4:
- self.parseError('Download URL')
+ self.error(_("No download URL"))
download_url = "http://%s.wrzuc.to/pobierz/%s" % (data['server_id'], data['download_link'])
- self.logDebug("Download URL: %s" % download_url)
self.download(download_url)
diff --git a/module/plugins/hoster/WuploadCom.py b/module/plugins/hoster/WuploadCom.py
index a0228081c..75ce59353 100644
--- a/module/plugins/hoster/WuploadCom.py
+++ b/module/plugins/hoster/WuploadCom.py
@@ -4,13 +4,16 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class WuploadCom(DeadHoster):
- __name__ = "WuploadCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?wupload\..*?/file/(([a-z][0-9]+/)?[0-9]+)(/.*)?'
+ __name__ = "WuploadCom"
+ __type__ = "hoster"
__version__ = "0.23"
+
+ __pattern__ = r'http://(?:www\.)?wupload\..+?/file/((\w+/)?\d+)(/.*)?'
+
__description__ = """Wupload.com hoster plugin"""
- __author_name__ = ("jeix", "Paul King")
- __author_mail__ = ("jeix@hasnomail.de", "")
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de"),
+ ("Paul King", None)]
getInfo = create_getInfo(WuploadCom)
diff --git a/module/plugins/hoster/X7To.py b/module/plugins/hoster/X7To.py
index 810ede911..a4e4b04bd 100644
--- a/module/plugins/hoster/X7To.py
+++ b/module/plugins/hoster/X7To.py
@@ -4,13 +4,15 @@ from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
class X7To(DeadHoster):
- __name__ = "X7To"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?x7.to/'
+ __name__ = "X7To"
+ __type__ = "hoster"
__version__ = "0.41"
+
+ __pattern__ = r'http://(?:www\.)?x7\.to/'
+
__description__ = """X7.to hoster plugin"""
- __author_name__ = "ernieb"
- __author_mail__ = "ernieb"
+ __license__ = "GPLv3"
+ __authors__ = [("ernieb", "ernieb")]
getInfo = create_getInfo(X7To)
diff --git a/module/plugins/hoster/XFileSharingPro.py b/module/plugins/hoster/XFileSharingPro.py
index 7ad2d27c0..0acad3dba 100644
--- a/module/plugins/hoster/XFileSharingPro.py
+++ b/module/plugins/hoster/XFileSharingPro.py
@@ -1,335 +1,57 @@
# -*- coding: utf-8 -*-
-###############################################################################
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License,
-# or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-###############################################################################
-
import re
-from random import random
-from urllib import unquote
-from urlparse import urlparse
-from pycurl import FOLLOWLOCATION, LOW_SPEED_TIME
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError, replace_patterns
-from module.plugins.internal.CaptchaService import ReCaptcha, SolveMedia
-from module.utils import html_unescape
-from module.network.RequestFactory import getURL
-
-
-class XFileSharingPro(SimpleHoster):
- """
- Common base for XFileSharingPro hosters like EasybytezCom, CramitIn, FiledinoCom...
- Some hosters may work straight away when added to __pattern__
- However, most of them will NOT work because they are either down or running a customized version
- """
- __name__ = "XFileSharingPro"
- __type__ = "hoster"
- __pattern__ = r'^unmatchable$'
- __version__ = "0.31"
- __description__ = """XFileSharingPro base hoster plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
-
- FILE_INFO_PATTERN = r'<tr><td align=right><b>Filename:</b></td><td nowrap>(?P<N>[^<]+)</td></tr>\s*.*?<small>\((?P<S>[^<]+)\)</small>'
- FILE_NAME_PATTERN = r'<input type="hidden" name="fname" value="(?P<N>[^"]+)"'
- FILE_SIZE_PATTERN = r'You have requested .*\((?P<S>[\d\.\,]+) ?(?P<U>\w+)?\)</font>'
- OFFLINE_PATTERN = r'>\w+ (Not Found|file (was|has been) removed)'
-
- WAIT_PATTERN = r'<span id="countdown_str">.*?>(\d+)</span>'
-
- OVR_LINK_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)'
-
- CAPTCHA_URL_PATTERN = r'(http://[^"\']+?/captchas?/[^"\']+)'
- RECAPTCHA_URL_PATTERN = r'http://[^"\']+?recaptcha[^"\']+?\?k=([^"\']+)"'
- CAPTCHA_DIV_PATTERN = r'>Enter code.*?<div.*?>(.*?)</div>'
- SOLVEMEDIA_PATTERN = r'http:\/\/api\.solvemedia\.com\/papi\/challenge\.script\?k=(.*?)"'
-
- ERROR_PATTERN = r'class=["\']err["\'][^>]*>(.*?)</'
-
-
- def setup(self):
- if self.__name__ == "XFileSharingPro":
- self.__pattern__ = self.core.pluginManager.hosterPlugins[self.__name__]['pattern']
- self.multiDL = True
- else:
- self.resumeDownload = self.multiDL = self.premium
-
- self.chunkLimit = 1
-
- def process(self, pyfile):
- self.prepare()
-
- pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS)
-
- if not re.match(self.__pattern__, pyfile.url):
- if self.premium:
- self.handleOverriden()
- else:
- self.fail("Only premium users can download from other hosters with %s" % self.HOSTER_NAME)
- else:
- try:
- # Due to a 0.4.9 core bug self.load would use cookies even if
- # cookies=False. Workaround using getURL to avoid cookies.
- # Can be reverted in 0.5 as the cookies bug has been fixed.
- self.html = getURL(pyfile.url, decode=True)
- self.file_info = self.getFileInfo()
- except PluginParseError:
- self.file_info = None
-
- self.location = self.getDirectDownloadLink()
-
- if not self.file_info:
- pyfile.name = html_unescape(unquote(urlparse(
- self.location if self.location else pyfile.url).path.split("/")[-1]))
-
- if self.location:
- self.startDownload(self.location)
- elif self.premium:
- self.handlePremium()
- else:
- self.handleFree()
-
- def prepare(self):
- """ Initialize important variables """
- if not hasattr(self, "HOSTER_NAME"):
- self.HOSTER_NAME = re.match(self.__pattern__, self.pyfile.url).group(1)
- if not hasattr(self, "LINK_PATTERN"):
- self.LINK_PATTERN = r'(http://([^/]*?%s|\d+\.\d+\.\d+\.\d+)(:\d+)?(/d/|(?:/files)?/\d+/\w+/)[^"\'<]+)' % self.HOSTER_NAME
-
- self.captcha = self.errmsg = None
- self.passwords = self.getPassword().splitlines()
-
- def getDirectDownloadLink(self):
- """ Get download link for premium users with direct download enabled """
- self.req.http.lastURL = self.pyfile.url
- self.req.http.c.setopt(FOLLOWLOCATION, 0)
- self.html = self.load(self.pyfile.url, cookies=True, decode=True)
- self.header = self.req.http.header
- self.req.http.c.setopt(FOLLOWLOCATION, 1)
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
- location = None
- m = re.search(r"Location\s*:\s*(.*)", self.header, re.I)
- if m and re.match(self.LINK_PATTERN, m.group(1)):
- location = m.group(1).strip()
- return location
+class XFileSharingPro(XFSHoster):
+ __name__ = "XFileSharingPro"
+ __type__ = "hoster"
+ __version__ = "0.43"
- def handleFree(self):
- url = self.getDownloadLink()
- self.logDebug("Download URL: %s" % url)
- self.startDownload(url)
-
- def getDownloadLink(self):
- for i in xrange(5):
- self.logDebug("Getting download link: #%d" % i)
- data = self.getPostParameters()
-
- self.req.http.c.setopt(FOLLOWLOCATION, 0)
- self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True)
- self.header = self.req.http.header
- self.req.http.c.setopt(FOLLOWLOCATION, 1)
-
- m = re.search(r"Location\s*:\s*(.*)", self.header, re.I)
- if m:
- break
-
- m = re.search(self.LINK_PATTERN, self.html, re.S)
- if m:
- break
+ __pattern__ = r'^unmatchable$'
- else:
- if self.errmsg and 'captcha' in self.errmsg:
- self.fail("No valid captcha code entered")
- else:
- self.fail("Download link not found")
+ __description__ = """XFileSharingPro dummy hoster plugin for hook"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- return m.group(1)
- def handlePremium(self):
- self.html = self.load(self.pyfile.url, post=self.getPostParameters())
- m = re.search(self.LINK_PATTERN, self.html)
- if m is None:
- self.parseError('DIRECT LINK')
- self.startDownload(m.group(1))
+ URL_REPLACEMENTS = [("/embed-", "/")]
- def handleOverriden(self):
- #only tested with easybytez.com
- self.html = self.load("http://www.%s/" % self.HOSTER_NAME)
- 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'] = self.pyfile.url
- inputs['up1oad_type'] = 'url'
- self.logDebug(self.HOSTER_NAME, action, inputs)
- #wait for file to upload to easybytez.com
- self.req.http.c.setopt(LOW_SPEED_TIME, 600)
- self.html = self.load(action, post=inputs)
+ 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())))
- action, inputs = self.parseHtmlForm('F1')
- if not inputs:
- self.parseError('TEXTAREA')
- self.logDebug(self.HOSTER_NAME, inputs)
- if inputs['st'] == 'OK':
- self.html = self.load(action, post=inputs)
- elif inputs['st'] == 'Can not leech file':
- self.retry(max_tries=20, wait_time=3 * 60, reason=inputs['st'])
- else:
- self.fail(inputs['st'])
- #get easybytez.com link for uploaded file
- m = re.search(self.OVR_LINK_PATTERN, self.html)
- if m is None:
- self.parseError('DIRECT LINK (OVR)')
- self.pyfile.url = m.group(1)
- header = self.load(self.pyfile.url, just_header=True)
- if 'location' in header: # Direct link
- self.startDownload(self.pyfile.url)
- else:
- self.retry()
+ def init(self):
+ super(XFileSharingPro, self).init()
- def startDownload(self, link):
- link = link.strip()
- if self.captcha:
- self.correctCaptcha()
- self.logDebug('DIRECT LINK: %s' % link)
- self.download(link, disposition=True)
+ self.__pattern__ = self.core.pluginManager.hosterPlugins[self.__name__]['pattern']
- def checkErrors(self):
- m = re.search(self.ERROR_PATTERN, self.html)
- if m:
- self.errmsg = m.group(1)
- self.logWarning(re.sub(r"<.*?>", " ", self.errmsg))
+ self.HOSTER_DOMAIN = re.match(self.__pattern__, self.pyfile.url).group(1).lower()
+ self.HOSTER_NAME = "".join([str.capitalize() for str in self.HOSTER_DOMAIN.split('.')])
- if 'wait' in self.errmsg:
- wait_time = sum([int(v) * {"hour": 3600, "minute": 60, "second": 1}[u] for v, u in
- re.findall(r'(\d+)\s*(hour|minute|second)?', self.errmsg)])
- self.wait(wait_time, True)
- 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:
- self.wait(1 * 60 * 60, True)
- self.retry(25)
- elif 'countdown' in self.errmsg or 'Expired' in self.errmsg:
- self.retry()
- elif 'maintenance' in self.errmsg:
- self.tempOffline()
- elif 'download files up to' in self.errmsg:
- self.fail("File too large for free download")
- else:
- self.fail(self.errmsg)
+ 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:
- self.errmsg = None
-
- return self.errmsg
-
- def getPostParameters(self):
- for _ in xrange(3):
- if not self.errmsg:
- self.checkErrors()
-
- if hasattr(self, "FORM_PATTERN"):
- action, inputs = self.parseHtmlForm(self.FORM_PATTERN)
- else:
- action, inputs = self.parseHtmlForm(input_names={"op": re.compile("^download")})
-
- if not inputs:
- action, inputs = self.parseHtmlForm('F1')
- if not inputs:
- if self.errmsg:
- self.retry()
- else:
- self.parseError("Form not found")
+ return
- self.logDebug(self.HOSTER_NAME, inputs)
+ self.user, data = self.account.selectAccount()
+ self.req = self.account.getAccountRequest(self.user)
+ self.premium = self.account.isPremium(self.user)
- if 'op' in inputs and inputs['op'] in ("download2", "download3"):
- if "password" in inputs:
- if self.passwords:
- inputs['password'] = self.passwords.pop(0)
- else:
- self.fail("No or invalid passport")
- if not self.premium:
- m = re.search(self.WAIT_PATTERN, self.html)
- if m:
- wait_time = int(m.group(1)) + 1
- self.setWait(wait_time, False)
- else:
- wait_time = 0
-
- self.captcha = self.handleCaptcha(inputs)
-
- if wait_time:
- self.wait()
-
- self.errmsg = None
- return inputs
-
- else:
- inputs['referer'] = self.pyfile.url
-
- if self.premium:
- inputs['method_premium'] = "Premium Download"
- if 'method_free' in inputs:
- del inputs['method_free']
- else:
- inputs['method_free'] = "Free Download"
- if 'method_premium' in inputs:
- del inputs['method_premium']
-
- self.html = self.load(self.pyfile.url, post=inputs, ref=True)
- self.errmsg = None
-
- else:
- self.parseError('FORM: %s' % (inputs['op'] if 'op' in inputs else 'UNKNOWN'))
-
- def handleCaptcha(self, inputs):
- m = re.search(self.RECAPTCHA_URL_PATTERN, self.html)
- if m:
- recaptcha_key = unquote(m.group(1))
- self.logDebug("RECAPTCHA KEY: %s" % recaptcha_key)
- recaptcha = ReCaptcha(self)
- inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(recaptcha_key)
- return 1
- else:
- m = re.search(self.CAPTCHA_URL_PATTERN, self.html)
- if m:
- captcha_url = m.group(1)
- inputs['code'] = self.decryptCaptcha(captcha_url)
- return 2
- else:
- m = re.search(self.CAPTCHA_DIV_PATTERN, self.html, re.DOTALL)
- if m:
- captcha_div = m.group(1)
- self.logDebug(captcha_div)
- numerals = re.findall(r'<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>', html_unescape(captcha_div))
- inputs['code'] = "".join([a[1] for a in sorted(numerals, key=lambda num: int(num[0]))])
- self.logDebug("CAPTCHA", inputs['code'], numerals)
- return 3
- else:
- m = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if m:
- captcha_key = m.group(1)
- captcha = SolveMedia(self)
- inputs['adcopy_challenge'], inputs['adcopy_response'] = captcha.challenge(captcha_key)
- return 4
- return 0
+ def setup(self):
+ self.chunkLimit = 1
+ self.resumeDownload = self.premium
+ self.multiDL = True
getInfo = create_getInfo(XFileSharingPro)
diff --git a/module/plugins/hoster/XHamsterCom.py b/module/plugins/hoster/XHamsterCom.py
index 9c93d4ee1..c6e789fa8 100644
--- a/module/plugins/hoster/XHamsterCom.py
+++ b/module/plugins/hoster/XHamsterCom.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
import re
+
from urllib import unquote
-from module.plugins.Hoster import Hoster
from module.common.json_layer import json_loads
+from module.plugins.Hoster import Hoster
def clean_json(json_expr):
@@ -16,12 +17,17 @@ def clean_json(json_expr):
class XHamsterCom(Hoster):
- __name__ = "XHamsterCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?xhamster\.com/movies/.+'
+ __name__ = "XHamsterCom"
+ __type__ = "hoster"
__version__ = "0.12"
+
+ __pattern__ = r'http://(?:www\.)?xhamster\.com/movies/.+'
__config__ = [("type", ".mp4;.flv", "Preferred type", ".mp4")]
+
__description__ = """XHamster.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = []
+
def process(self, pyfile):
self.pyfile = pyfile
@@ -35,21 +41,23 @@ class XHamsterCom(Hoster):
pyfile.name = self.get_file_name() + self.desired_fmt
self.download(self.get_file_url())
+
def download_html(self):
url = self.pyfile.url
self.html = self.load(url)
+
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
if not self.html:
self.download_html()
- flashvar_pattern = re.compile('flashvars = ({.*?});', re.DOTALL)
+ flashvar_pattern = re.compile('flashvars = ({.*?});', re.S)
json_flashvar = flashvar_pattern.search(self.html)
if not json_flashvar:
- self.fail("Parse error (flashvars)")
+ self.error(_("flashvar not found"))
j = clean_json(json_flashvar.group(1))
flashvars = json_loads(j)
@@ -57,55 +65,59 @@ class XHamsterCom(Hoster):
if flashvars['srv']:
srv_url = flashvars['srv'] + '/'
else:
- self.fail("Parse error (srv_url)")
+ self.error(_("srv_url not found"))
if flashvars['url_mode']:
url_mode = flashvars['url_mode']
+
+
else:
- self.fail("Parse error (url_mode)")
+ self.error(_("url_mode not found"))
if self.desired_fmt == ".mp4":
file_url = re.search(r"<a href=\"" + srv_url + "(.+?)\"", self.html)
if file_url is None:
- self.fail("Parse error (file_url)")
+ self.error(_("file_url not found"))
file_url = file_url.group(1)
long_url = srv_url + file_url
- self.logDebug("long_url: %s" % long_url)
+ self.logDebug("long_url = " + long_url)
else:
if flashvars['file']:
file_url = unquote(flashvars['file'])
else:
- self.fail("Parse error (file_url)")
+ self.error(_("file_url not found"))
if url_mode == '3':
long_url = file_url
- self.logDebug("long_url: %s" % long_url)
+ self.logDebug("long_url = " + long_url)
else:
long_url = srv_url + "key=" + file_url
- self.logDebug("long_url: %s" % long_url)
+ self.logDebug("long_url = " + long_url)
return long_url
+
def get_file_name(self):
if not self.html:
self.download_html()
- pattern = r"<title>(.*?) - xHamster\.com</title>"
+ pattern = r'<title>(.*?) - xHamster\.com</title>'
name = re.search(pattern, self.html)
if name is None:
- pattern = r"<h1 >(.*)</h1>"
+ pattern = r'<h1 >(.*)</h1>'
name = re.search(pattern, self.html)
if name is None:
- pattern = r"http://[www.]+xhamster\.com/movies/.*/(.*?)\.html?"
+ pattern = r'http://[www.]+xhamster\.com/movies/.*/(.*?)\.html?'
name = re.match(file_name_pattern, self.pyfile.url)
if name is None:
- pattern = r"<div id=\"element_str_id\" style=\"display:none;\">(.*)</div>"
+ pattern = r'<div id="element_str_id" style="display:none;">(.*)</div>'
name = re.search(pattern, self.html)
if name is None:
return "Unknown"
return name.group(1)
+
def file_exists(self):
""" returns True or False
"""
diff --git a/module/plugins/hoster/XVideosCom.py b/module/plugins/hoster/XVideosCom.py
index 76dfdadad..9bb2da424 100644
--- a/module/plugins/hoster/XVideosCom.py
+++ b/module/plugins/hoster/XVideosCom.py
@@ -1,18 +1,23 @@
# -*- coding: utf-8 -*-
import re
-import urllib
+
+from urllib import unquote
from module.plugins.Hoster import Hoster
class XVideosCom(Hoster):
- __name__ = "XVideos.com"
- __version__ = "0.1"
- __pattern__ = r'http://(?:www\.)?xvideos\.com/video([0-9]+)/.*'
+ __name__ = "XVideos.com"
+ __type__ = "hoster"
+ __version__ = "0.10"
+
+ __pattern__ = r'http://(?:www\.)?xvideos\.com/video(\d+)'
+
__description__ = """XVideos.com hoster plugin"""
- __author_name__ = None
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = []
+
def process(self, pyfile):
site = self.load(pyfile.url)
@@ -20,4 +25,4 @@ class XVideosCom(Hoster):
re.search(r"<h2>([^<]+)<span", site).group(1),
re.match(self.__pattern__, pyfile.url).group(1),
)
- self.download(urllib.unquote(re.search(r"flv_url=([^&]+)&", site).group(1)))
+ self.download(unquote(re.search(r"flv_url=([^&]+)&", site).group(1)))
diff --git a/module/plugins/hoster/Xdcc.py b/module/plugins/hoster/Xdcc.py
index 8f3fb284f..ef6da4a71 100644
--- a/module/plugins/hoster/Xdcc.py
+++ b/module/plugins/hoster/Xdcc.py
@@ -1,60 +1,48 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-from os.path import join
-from os.path import exists
-from os import makedirs
import re
-import sys
-import time
import socket
import struct
+import sys
+import time
+
+from os import makedirs
+from os.path import exists, join
from select import select
-from module.utils import save_join
from module.plugins.Hoster import Hoster
+from module.utils import save_join
class Xdcc(Hoster):
- __name__ = "Xdcc"
+ __name__ = "Xdcc"
+ __type__ = "hoster"
__version__ = "0.32"
- __pattern__ = r'xdcc://([^/]*?)(/#?.*?)?/.*?/#?\d+/?' # xdcc://irc.Abjects.net/#channel/[XDCC]|Shit/#0004/
- __type__ = "hoster"
+
__config__ = [("nick", "str", "Nickname", "pyload"),
("ident", "str", "Ident", "pyloadident"),
("realname", "str", "Realname", "pyloadreal")]
+
__description__ = """Download from IRC XDCC bot"""
- __author_name__ = "jeix"
- __author_mail__ = "jeix@hasnomail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.com")]
+
def setup(self):
self.debug = 0 # 0,1,2
self.timeout = 30
self.multiDL = False
+
def process(self, pyfile):
# change request type
self.req = pyfile.m.core.requestFactory.getRequest(self.__name__, type="XDCC")
self.pyfile = pyfile
- for _ in xrange(0, 3):
+ for _i in xrange(0, 3):
try:
nmn = self.doDownload(pyfile.url)
- self.logDebug("%s: Download of %s finished." % (self.__name__, nmn))
+ self.logDebug("Download of %s finished." % nmn)
return
except socket.error, e:
if hasattr(e, "errno"):
@@ -63,23 +51,19 @@ class Xdcc(Hoster):
errno = e.args[0]
if errno == 10054:
- self.logDebug("XDCC: Server blocked our ip, retry in 5 min")
+ self.logDebug("Server blocked our ip, retry in 5 min")
self.setWait(300)
self.wait()
continue
- self.fail("Failed due to socket errors. Code: %d" % errno)
+ self.fail(_("Failed due to socket errors. Code: %d") % errno)
+
+ self.fail(_("Server blocked our ip, retry again later manually"))
- self.fail("Server blocked our ip, retry again later manually")
def doDownload(self, url):
self.pyfile.setStatus("waiting") # real link
- download_folder = self.config['general']['download_folder']
- location = join(download_folder, self.pyfile.package().folder.decode(sys.getfilesystemencoding()))
- if not exists(location):
- makedirs(location)
-
m = re.match(r'xdcc://(.*?)/#?(.*?)/(.*?)/#?(\d+)/?', url)
server = m.group(1)
chan = m.group(2)
@@ -96,7 +80,7 @@ class Xdcc(Hoster):
elif ln == 1:
host, port = temp[0], 6667
else:
- self.fail("Invalid hostname for IRC Server (%s)" % server)
+ self.fail(_("Invalid hostname for IRC Server: %s") % server)
#######################
# CONNECT TO IRC AND IDLE FOR REAL LINK
@@ -133,7 +117,7 @@ class Xdcc(Hoster):
if (dl_time + self.timeout) < time.time(): # todo: add in config
sock.send("QUIT :byebye\r\n")
sock.close()
- self.fail("XDCC Bot did not answer")
+ self.fail(_("XDCC Bot did not answer"))
fdset = select([sock], [], [], 0)
if sock not in fdset[0]:
@@ -153,7 +137,7 @@ class Xdcc(Hoster):
sock.send("PONG %s\r\n" % first[1])
if first[0] == "ERROR":
- self.fail("IRC-Error: %s" % line)
+ self.fail(_("IRC-Error: %s") % line)
msg = line.split(None, 3)
if len(msg) != 4:
@@ -168,10 +152,10 @@ class Xdcc(Hoster):
if nick == msg['target'][0:len(nick)] and "PRIVMSG" == msg['action']:
if msg['text'] == "\x01VERSION\x01":
- self.logDebug("XDCC: Sending CTCP VERSION.")
+ self.logDebug("Sending CTCP VERSION")
sock.send("NOTICE %s :%s\r\n" % (msg['origin'], "pyLoad! IRC Interface"))
elif msg['text'] == "\x01TIME\x01":
- self.logDebug("Sending CTCP TIME.")
+ self.logDebug("Sending CTCP TIME")
sock.send("NOTICE %s :%d\r\n" % (msg['origin'], time.time()))
elif msg['text'] == "\x01LAG\x01":
pass # don't know how to answer
@@ -188,7 +172,7 @@ class Xdcc(Hoster):
retry = time.time() + 300
if "you must be on a known channel to request a pack" in msg['text']:
- self.fail("Wrong channel")
+ self.fail(_("Wrong channel"))
m = re.match('\x01DCC SEND (.*?) (\d+) (\d+)(?: (\d+))?\x01', msg['text'])
if m:
@@ -203,13 +187,16 @@ class Xdcc(Hoster):
self.req.filesize = int(m.group(4))
self.pyfile.name = packname
- filename = save_join(location, packname)
- self.logInfo("XDCC: Downloading %s from %s:%d" % (packname, ip, port))
+
+ download_folder = self.config['general']['download_folder']
+ filename = save_join(download_folder, packname)
+
+ self.logInfo(_("Downloading %s from %s:%d") % (packname, ip, port))
self.pyfile.setStatus("downloading")
newname = self.req.download(ip, port, filename, sock, self.pyfile.setProgress)
if newname and newname != filename:
- self.logInfo("%(name)s saved as %(newname)s" % {"name": self.pyfile.name, "newname": newname})
+ self.logInfo(_("%(name)s saved as %(newname)s") % {"name": self.pyfile.name, "newname": newname})
filename = newname
# kill IRC socket
diff --git a/module/plugins/hoster/YibaishiwuCom.py b/module/plugins/hoster/YibaishiwuCom.py
index 44a67ec0c..3b4692933 100644
--- a/module/plugins/hoster/YibaishiwuCom.py
+++ b/module/plugins/hoster/YibaishiwuCom.py
@@ -1,36 +1,25 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
from module.common.json_layer import json_loads
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class YibaishiwuCom(SimpleHoster):
- __name__ = "YibaishiwuCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(?:u\.)?115.com/file/(?P<ID>\w+)'
- __version__ = "0.12"
+ __name__ = "YibaishiwuCom"
+ __type__ = "hoster"
+ __version__ = "0.13"
+
+ __pattern__ = r'http://(?:www\.)?(?:u\.)?115\.com/file/(?P<ID>\w+)'
+
__description__ = """115.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_NAME_PATTERN = r"file_name: '(?P<N>[^']+)'"
- FILE_SIZE_PATTERN = r"file_size: '(?P<S>[^']+)'"
+ 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_PATTERN = r'(/\?ct=(pickcode|download)[^"\']+)'
@@ -39,15 +28,15 @@ class YibaishiwuCom(SimpleHoster):
def handleFree(self):
m = re.search(self.LINK_PATTERN, self.html)
if m is None:
- self.parseError("AJAX URL")
+ self.error(_("LINK_PATTERN not found"))
url = m.group(1)
self.logDebug(('FREEUSER' if m.group(2) == 'download' else 'GUEST') + ' URL', url)
- response = json_loads(self.load("http://115.com" + url, decode=False))
- if "urls" in response:
- mirrors = response['urls']
- elif "data" in response:
- mirrors = response['data']
+ 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
@@ -60,7 +49,7 @@ class YibaishiwuCom(SimpleHoster):
except:
continue
else:
- self.fail('No working link found')
+ self.fail(_("No working link found"))
getInfo = create_getInfo(YibaishiwuCom)
diff --git a/module/plugins/hoster/YoupornCom.py b/module/plugins/hoster/YoupornCom.py
index f8f782f1c..4bb2520e6 100644
--- a/module/plugins/hoster/YoupornCom.py
+++ b/module/plugins/hoster/YoupornCom.py
@@ -1,17 +1,21 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.Hoster import Hoster
class YoupornCom(Hoster):
- __name__ = "YoupornCom"
- __type__ = "hoster"
+ __name__ = "YoupornCom"
+ __type__ = "hoster"
+ __version__ = "0.20"
+
__pattern__ = r'http://(?:www\.)?youporn\.com/watch/.+'
- __version__ = "0.2"
+
__description__ = """Youporn.com hoster plugin"""
- __author_name__ = "willnix"
- __author_mail__ = "willnix@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("willnix", "willnix@pyload.org")]
+
def process(self, pyfile):
self.pyfile = pyfile
@@ -22,10 +26,12 @@ class YoupornCom(Hoster):
pyfile.name = self.get_file_name()
self.download(self.get_file_url())
+
def download_html(self):
url = self.pyfile.url
self.html = self.load(url, post={"user_choice": "Enter"}, cookies=False)
+
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
@@ -34,13 +40,15 @@ class YoupornCom(Hoster):
return re.search(r'(http://download\.youporn\.com/download/\d+\?save=1)">', self.html).group(1)
+
def get_file_name(self):
if not self.html:
self.download_html()
- file_name_pattern = r"<title>(.*) - Free Porn Videos - YouPorn</title>"
+ file_name_pattern = r'<title>(.+) - '
return re.search(file_name_pattern, self.html).group(1).replace("&amp;", "&").replace("/", "") + '.flv'
+
def file_exists(self):
""" returns True or False
"""
diff --git a/module/plugins/hoster/YourfilesTo.py b/module/plugins/hoster/YourfilesTo.py
index 3fb517eef..83ab89110 100644
--- a/module/plugins/hoster/YourfilesTo.py
+++ b/module/plugins/hoster/YourfilesTo.py
@@ -1,24 +1,31 @@
# -*- coding: utf-8 -*-
import re
-import urllib
+
+from urllib import unquote
+
from module.plugins.Hoster import Hoster
class YourfilesTo(Hoster):
- __name__ = "YourfilesTo"
- __type__ = "hoster"
- __pattern__ = r'(http://)?(?:www\.)?yourfiles\.(to|biz)/\?d=[a-zA-Z0-9]+'
+ __name__ = "YourfilesTo"
+ __type__ = "hoster"
__version__ = "0.21"
+
+ __pattern__ = r'(http://)?(?:www\.)?yourfiles\.(to|biz)/\?d=\w+'
+
__description__ = """Youfiles.to hoster plugin"""
- __author_name__ = ("jeix", "skydancer")
- __author_mail__ = ("jeix@hasnomail.de", "skydancer@hasnomail.de")
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de"),
+ ("skydancer", "skydancer@hasnomail.de")]
+
def process(self, pyfile):
self.pyfile = pyfile
self.prepare()
self.download(self.get_file_url())
+
def prepare(self):
if not self.file_exists():
self.offline()
@@ -27,9 +34,9 @@ class YourfilesTo(Hoster):
wait_time = self.get_waiting_time()
self.setWait(wait_time)
- self.logDebug("%s: Waiting %d seconds." % (self.__name__, wait_time))
self.wait()
+
def get_waiting_time(self):
if not self.html:
self.download_html()
@@ -43,20 +50,23 @@ class YourfilesTo(Hoster):
return sec
+
def download_html(self):
url = self.pyfile.url
self.html = self.load(url)
+
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
url = re.search(r"var bla = '(.*?)';", self.html)
if url:
url = url.group(1)
- url = urllib.unquote(url.replace("http://http:/http://", "http://").replace("dumdidum", ""))
+ url = unquote(url.replace("http://http:/http://", "http://").replace("dumdidum", ""))
return url
else:
- self.fail("absolute filepath could not be found. offline? ")
+ self.error(_("Absolute filepath not found"))
+
def get_file_name(self):
if not self.html:
@@ -64,6 +74,7 @@ class YourfilesTo(Hoster):
return re.search("<title>(.*)</title>", self.html).group(1)
+
def file_exists(self):
""" returns True or False
"""
diff --git a/module/plugins/hoster/YoutubeCom.py b/module/plugins/hoster/YoutubeCom.py
index d9dc5e0ef..90c6df3c2 100644
--- a/module/plugins/hoster/YoutubeCom.py
+++ b/module/plugins/hoster/YoutubeCom.py
@@ -1,13 +1,14 @@
# -*- coding: utf-8 -*-
+import os
import re
import subprocess
-import os
+
from urllib import unquote
-from module.utils import html_unescape
from module.plugins.Hoster import Hoster
from module.plugins.internal.SimpleHoster import replace_patterns
+from module.utils import html_unescape
def which(program):
@@ -19,6 +20,7 @@ def which(program):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
+
if fpath:
if is_exe(program):
return program
@@ -33,10 +35,11 @@ def which(program):
class YoutubeCom(Hoster):
- __name__ = "YoutubeCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:[^/]*\.)?(?:youtube\.com|youtu\.be)/watch.*?[?&]v=.*'
+ __name__ = "YoutubeCom"
+ __type__ = "hoster"
__version__ = "0.40"
+
+ __pattern__ = r'https?://(?:[^/]*\.)?(?:youtube\.com|youtu\.be)/watch.*?[?&]v=.+'
__config__ = [("quality", "sd;hd;fullhd;240p;360p;480p;720p;1080p;3072p", "Quality Setting", "hd"),
("fmt", "int", "FMT/ITAG Number (5-102, 0 for auto)", 0),
(".mp4", "bool", "Allow .mp4", True),
@@ -44,43 +47,49 @@ class YoutubeCom(Hoster):
(".webm", "bool", "Allow .webm", False),
(".3gp", "bool", "Allow .3gp", False),
("3d", "bool", "Prefer 3D", False)]
+
__description__ = """Youtube.com hoster plugin"""
- __author_name__ = ("spoob", "zoidberg")
- __author_mail__ = ("spoob@pyload.org", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
- FILE_URL_REPLACEMENTS = [(r'youtu\.be/', 'youtube.com/')]
+ URL_REPLACEMENTS = [(r'youtu\.be/', 'youtube.com/')]
# Invalid characters that must be removed from the file name
invalidChars = u'\u2605:?><"|\\'
# name, width, height, quality ranking, 3D
- formats = {5: (".flv", 400, 240, 1, False),
- 6: (".flv", 640, 400, 4, False),
- 17: (".3gp", 176, 144, 0, False),
- 18: (".mp4", 480, 360, 2, False),
- 22: (".mp4", 1280, 720, 8, False),
- 43: (".webm", 640, 360, 3, False),
- 34: (".flv", 640, 360, 4, False),
- 35: (".flv", 854, 480, 6, False),
- 36: (".3gp", 400, 240, 1, False),
- 37: (".mp4", 1920, 1080, 9, False),
- 38: (".mp4", 4096, 3072, 10, False),
- 44: (".webm", 854, 480, 5, False),
- 45: (".webm", 1280, 720, 7, False),
- 46: (".webm", 1920, 1080, 9, False),
- 82: (".mp4", 640, 360, 3, True),
- 83: (".mp4", 400, 240, 1, True),
- 84: (".mp4", 1280, 720, 8, True),
- 85: (".mp4", 1920, 1080, 9, True),
- 100: (".webm", 640, 360, 3, True),
- 101: (".webm", 640, 360, 4, True),
- 102: (".webm", 1280, 720, 8, True)}
+ formats = {5 : (".flv" , 400 , 240 , 1 , False),
+ 6 : (".flv" , 640 , 400 , 4 , False),
+ 17 : (".3gp" , 176 , 144 , 0 , False),
+ 18 : (".mp4" , 480 , 360 , 2 , False),
+ 22 : (".mp4" , 1280, 720 , 8 , False),
+ 43 : (".webm", 640 , 360 , 3 , False),
+ 34 : (".flv" , 640 , 360 , 4 , False),
+ 35 : (".flv" , 854 , 480 , 6 , False),
+ 36 : (".3gp" , 400 , 240 , 1 , False),
+ 37 : (".mp4" , 1920, 1080, 9 , False),
+ 38 : (".mp4" , 4096, 3072, 10, False),
+ 44 : (".webm", 854 , 480 , 5 , False),
+ 45 : (".webm", 1280, 720 , 7 , False),
+ 46 : (".webm", 1920, 1080, 9 , False),
+ 82 : (".mp4" , 640 , 360 , 3 , True ),
+ 83 : (".mp4" , 400 , 240 , 1 , True ),
+ 84 : (".mp4" , 1280, 720 , 8 , True ),
+ 85 : (".mp4" , 1920, 1080, 9 , True ),
+ 100: (".webm", 640 , 360 , 3 , True ),
+ 101: (".webm", 640 , 360 , 4 , True ),
+ 102: (".webm", 1280, 720 , 8 , True )}
+
def setup(self):
- self.resumeDownload = self.multiDL = True
+ self.resumeDownload = True
+ self.multiDL = True
+
def process(self, pyfile):
- pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS)
+ pyfile.url = replace_patterns(pyfile.url, self.URL_REPLACEMENTS)
html = self.load(pyfile.url, decode=True)
if re.search(r'<div id="player-unavailable" class="\s*player-width player-height\s*">', html):
@@ -99,7 +108,7 @@ class YoutubeCom(Hoster):
"480p": 35, "720p": 22, "1080p": 37, "3072p": 38}
desired_fmt = self.getConfig("fmt")
if desired_fmt and desired_fmt not in self.formats:
- self.logWarning("FMT %d unknown - using default." % desired_fmt)
+ self.logWarning(_("FMT %d unknown, using default") % desired_fmt)
desired_fmt = 0
if not desired_fmt:
desired_fmt = quality.get(self.getConfig("quality"), 18)
@@ -116,7 +125,7 @@ class YoutubeCom(Hoster):
allowed = lambda x: self.getConfig(self.formats[x][0])
streams = [x for x in streams if x[0] in self.formats and allowed(x[0])]
if not streams:
- self.fail("No available stream meets your preferences")
+ self.fail(_("No available stream meets your preferences"))
fmt_dict = dict([x for x in streams if self.formats[x[0]][4] == use3d] or streams)
self.logDebug("DESIRED STREAM: ITAG:%d (%s) %sfound, %sallowed" %
diff --git a/module/plugins/hoster/ZDF.py b/module/plugins/hoster/ZDF.py
index 3c9c6ce9a..8d3de5b26 100644
--- a/module/plugins/hoster/ZDF.py
+++ b/module/plugins/hoster/ZDF.py
@@ -1,22 +1,26 @@
# -*- coding: utf-8 -*-
import re
+
from xml.etree.ElementTree import fromstring
from module.plugins.Hoster import Hoster
-XML_API = "http://www.zdf.de/ZDFmediathek/xmlservice/web/beitragsDetails?id=%i"
-
+# Based on zdfm by Roland Beermann (http://github.com/enkore/zdfm/)
class ZDF(Hoster):
- # Based on zdfm by Roland Beermann
- # http://github.com/enkore/zdfm/
- __name__ = "ZDF Mediathek"
- __version__ = "0.8"
- __pattern__ = r'http://(?:www\.)?zdf\.de/ZDFmediathek/[^0-9]*([0-9]+)[^0-9]*'
+ __name__ = "ZDF Mediathek"
+ __type__ = "hoster"
+ __version__ = "0.80"
+
+ __pattern__ = r'http://(?:www\.)?zdf\.de/ZDFmediathek/\D*(\d+)\D*'
+
__description__ = """ZDF.de hoster plugin"""
- __author_name__ = None
- __author_mail__ = None
+ __license__ = "GPLv3"
+ __authors__ = []
+
+ XML_API = "http://www.zdf.de/ZDFmediathek/xmlservice/web/beitragsDetails?id=%i"
+
@staticmethod
def video_key(video):
@@ -25,21 +29,24 @@ class ZDF(Hoster):
any(f.text == "progressive" for f in video.iter("facet")),
)
+
@staticmethod
def video_valid(video):
return video.findtext("url").startswith("http") and video.findtext("url").endswith(".mp4") and \
video.findtext("facets/facet").startswith("progressive")
+
@staticmethod
def get_id(url):
- return int(re.search(r"[^0-9]*([0-9]{4,})[^0-9]*", url).group(1))
+ return int(re.search(r"\D*(\d{4,})\D*", url).group(1))
+
def process(self, pyfile):
- xml = fromstring(self.load(XML_API % self.get_id(pyfile.url)))
+ xml = fromstring(self.load(self.XML_API % self.get_id(pyfile.url)))
status = xml.findtext("./status/statuscode")
if status != "ok":
- self.fail("Error retrieving manifest.")
+ self.fail(_("Error retrieving manifest"))
video = xml.find("video")
title = video.findtext("information/title")
diff --git a/module/plugins/hoster/ZShareNet.py b/module/plugins/hoster/ZShareNet.py
new file mode 100644
index 000000000..dc96facbe
--- /dev/null
+++ b/module/plugins/hoster/ZShareNet.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.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", None),
+ ("Cptn Sandwich", None)]
+
+
+getInfo = create_getInfo(ZShareNet)
diff --git a/module/plugins/hoster/ZeveraCom.py b/module/plugins/hoster/ZeveraCom.py
index d3d67bedc..40ef5de0f 100644
--- a/module/plugins/hoster/ZeveraCom.py
+++ b/module/plugins/hoster/ZeveraCom.py
@@ -1,105 +1,42 @@
# -*- coding: utf-8 -*-
-from module.plugins.Hoster import Hoster
+from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo
-class ZeveraCom(Hoster):
- __name__ = "ZeveraCom"
- __version__ = "0.21"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?zevera.com/.*'
+class ZeveraCom(MultiHoster):
+ __name__ = "ZeveraCom"
+ __type__ = "hoster"
+ __version__ = "0.25"
+
+ __pattern__ = r'http://(?:www\.)?zevera\.com/.+'
+
__description__ = """Zevera.com hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- def setup(self):
- self.resumeDownload = self.multiDL = True
- self.chunkLimit = 1
- def process(self, pyfile):
- if not self.account:
- self.logError(_("Please enter your %s account or deactivate this plugin") % "zevera.com")
- self.fail("No zevera.com account provided")
+ def setup(self):
+ self.resumeDownload = True
+ self.multiDL = True
+ self.chunkLimit = 1
- self.logDebug("zevera.com: Old URL: %s" % pyfile.url)
- if self.account.getAPIData(self.req, cmd="checklink", olink=pyfile.url) != "Alive":
- self.fail("Offline or not downloadable - contact Zevera support")
+ def handlePremium(self):
+ if self.account.getAPIData(self.req, cmd="checklink", olink=self.pyfile.url) != "Alive":
+ self.fail(_("Offline or not downloadable"))
- header = self.account.getAPIData(self.req, just_header=True, cmd="generatedownloaddirect", olink=pyfile.url)
+ header = self.account.getAPIData(self.req, just_header=True, cmd="generatedownloaddirect", olink=self.pyfile.url)
if not "location" in header:
- self.fail("Unable to initialize download - contact Zevera support")
-
- self.download(header['location'], disposition=True)
-
- check = self.checkDownload({"error": 'action="ErrorDownload.aspx'})
- if check == "error":
- self.fail("Error response received - contact Zevera support")
-
- # BitAPI not used - defunct, probably abandoned by Zevera
- #
- # api_url = "http://zevera.com/API.ashx"
- #
- # def process(self, pyfile):
- # if not self.account:
- # self.logError(_("Please enter your zevera.com account or deactivate this plugin"))
- # self.fail("No zevera.com account provided")
- #
- # self.logDebug("zevera.com: Old URL: %s" % pyfile.url)
- #
- # last_size = retries = 0
- # olink = pyfile.url #quote(pyfile.url.encode('utf_8'))
- #
- # for _ in xrange(100):
- # self.retData = self.account.loadAPIRequest(self.req, cmd = 'download_request', olink = olink)
- # self.checkAPIErrors(self.retData)
- #
- # if self.retData['FileInfo']['StatusID'] == 100:
- # break
- # elif self.retData['FileInfo']['StatusID'] == 99:
- # self.fail('Failed to initialize download (99)')
- # else:
- # if self.retData['FileInfo']['Progress']['BytesReceived'] <= last_size:
- # if retries >= 6:
- # self.fail('Failed to initialize download (%d)' % self.retData['FileInfo']['StatusID'] )
- # retries += 1
- # else:
- # retries = 0
- #
- # last_size = self.retData['FileInfo']['Progress']['BytesReceived']
- #
- # self.setWait(self.retData['Update_Wait'])
- # self.wait()
- #
- # pyfile.name = self.retData['FileInfo']['RealFileName']
- # pyfile.size = self.retData['FileInfo']['FileSizeInBytes']
- #
- # self.retData = self.account.loadAPIRequest(self.req, cmd = 'download_start',
- # FileID = self.retData['FileInfo']['FileID'])
- # self.checkAPIErrors(self.retData)
- #
- # self.download(self.api_url, get = {
- # 'cmd': "open_stream",
- # 'login': self.account.loginname,
- # 'pass': self.account.password,
- # 'FileID': self.retData['FileInfo']['FileID'],
- # 'startBytes': 0
- # }
- # )
- #
- # def checkAPIErrors(self, retData):
- # if not retData:
- # self.fail('Unknown API response')
- #
- # if retData['ErrorCode']:
- # self.logError(retData['ErrorCode'], retData['ErrorMessage'])
- # #self.fail('ERROR: ' + retData['ErrorMessage'])
- #
- # if pyfile.size / 1024000 > retData['AccountInfo']['AvailableTODAYTrafficForUseInMBytes']:
- # self.logWarning("Not enough data left to download the file")
- #
- # def crazyDecode(self, ustring):
- # # accepts decoded ie. unicode string - API response is double-quoted, double-utf8-encoded
- # # no idea what the proper order of calling these functions would be :-/
- # return html_unescape(unquote(unquote(ustring.replace(
- # '@DELIMITER@','#'))).encode('raw_unicode_escape').decode('utf-8'))
+ self.fail(_("Unable to initialize download"))
+
+ self.link = header['location']
+
+
+ def checkFile(self):
+ super(ZeveraCom, self).checkFile()
+
+ if self.checkDownload({"error": 'action="ErrorDownload.aspx'}) is "error":
+ self.fail(_("Error response received - contact Zevera support"))
+
+
+getInfo = create_getInfo(ZeveraCom)
diff --git a/module/plugins/hoster/ZippyshareCom.py b/module/plugins/hoster/ZippyshareCom.py
index 0c04d68e5..67b384c5f 100644
--- a/module/plugins/hoster/ZippyshareCom.py
+++ b/module/plugins/hoster/ZippyshareCom.py
@@ -1,72 +1,64 @@
# -*- coding: utf-8 -*-
-# Test links (random.bin):
-# http://www13.zippyshare.com/v/18665333/file.html
-
import re
+from urlparse import urljoin
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class ZippyshareCom(SimpleHoster):
- __name__ = "ZippyshareCom"
- __type__ = "hoster"
- __pattern__ = r'(?P<HOST>http://www\d{0,2}\.zippyshare.com)/v(?:/|iew.jsp.*key=)(?P<KEY>\d+)'
- __version__ = "0.49"
+ __name__ = "ZippyshareCom"
+ __type__ = "hoster"
+ __version__ = "0.63"
+
+ __pattern__ = r'(?P<HOST>http://www\d{0,2}\.zippyshare\.com)/v(?:/|iew\.jsp.*key=)(?P<KEY>\d+)'
+
__description__ = """Zippyshare.com hoster plugin"""
- __author_name__ = ("spoob", "zoidberg", "stickell", "skylab")
- __author_mail__ = ("spoob@pyload.org", "zoidberg@mujmail.cz", "l.stickell@yahoo.it", "development@sky-lab.de")
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
- FILE_NAME_PATTERN = r'<title>Zippyshare\.com - (?P<N>[^<]+)</title>'
- FILE_SIZE_PATTERN = r'>Size:</font>\s*<font [^>]*>(?P<S>[0-9.,]+) (?P<U>[kKMG]+)i?B</font><br />'
- FILE_INFO_PATTERN = r'document\.getElementById\(\'dlbutton\'\)\.href = "[^;]*/(?P<N>[^"]+)";'
- OFFLINE_PATTERN = r'>File does not exist on this server</div>'
+ NAME_PATTERN = r'("\d{6,}/"[ ]*\+.+?"/|<title>Zippyshare.com - )(?P<N>.+?)("|</title>)'
+ SIZE_PATTERN = r'>Size:.+?">(?P<S>[\d.,]+) (?P<U>[\w^_]+)'
- SH_COOKIES = [(".zippyshare.com", "ziplocale", "en")]
+ OFFLINE_PATTERN = r'>File does not exist on this server<'
+
+ COOKIES = [("zippyshare.com", "ziplocale", "en")]
def setup(self):
self.multiDL = True
+ self.chunkLimit = -1
+ self.resumeDownload = True
+
def handleFree(self):
- url = self.get_file_url()
- if not url:
- self.fail("Download URL not found.")
- self.logDebug("Download URL: %s" % url)
+ url = self.get_link()
self.download(url)
- def get_file_url(self):
- """returns the absolute downloadable filepath"""
- url_parts = re.search(r'(addthis:url="(http://www(\d+).zippyshare.com/v/(\d*)/file.html))', self.html)
- number = url_parts.group(4)
- check = re.search(r'<script type="text/javascript">([^<]*?)(var a = (\d*);)', self.html)
- if check:
- a = int(re.search(r'<script type="text/javascript">([^<]*?)(var a = (\d*);)', self.html).group(3))
- k = int(re.search(r'<script type="text/javascript">([^<]*?)(\d*%(\d*))', self.html).group(3))
- checksum = ((a + 3) % k) * ((a + 3) % 3) + 18
- else:
- # This might work but is insecure
- # checksum = eval(re.search("((\d*)\s\%\s(\d*)\s\+\s(\d*)\s\%\s(\d*))", self.html).group(0))
-
- m = re.search(r"((?P<a>\d*)\s%\s(?P<b>\d*)\s\+\s(?P<c>\d*)\s%\s(?P<k>\d*))", self.html)
- if m is None:
- self.parseError("Unable to detect values to calculate direct link")
- a = int(m.group("a"))
- b = int(m.group("b"))
- c = int(m.group("c"))
- k = int(m.group("k"))
- if a == c:
- checksum = ((a % b) + (a % k))
+
+ def get_checksum(self):
+ try:
+ m = re.search(r'\+[ ]*\((\d+)[ ]*\%[ ]*(\d+)[ ]*\+[ ]*(\d+)[ ]*\%[ ]*(\d+)\)[ ]*\+', self.html)
+ if m:
+ a1, a2, c1, c2 = map(int, m.groups())
else:
- checksum = ((a % b) + (c % k))
+ a1, a2 = map(int, re.search(r'\(\'downloadB\'\).omg = (\d+)%(\d+)', self.html).groups())
+ c1, c2 = map(int, re.search(r'\(\'downloadB\'\).omg\) \* \((\d+)%(\d+)', self.html).groups())
- self.logInfo('Checksum: %s' % checksum)
+ b = (a1 % a2) * (c1 % c2)
+ except:
+ self.error(_("Unable to calculate checksum"))
+ else:
+ return b + 18
- filename = re.search(r'>Name:</font>\s*<font [^>]*>(?P<N>[^<]+)</font><br />', self.html).group('N')
- url = "/d/%s/%s/%s" % (number, checksum, filename)
- self.logInfo(self.file_info['HOST'] + url)
- return self.file_info['HOST'] + url
+ def get_link(self):
+ checksum = self.get_checksum()
+ p_url = '/'.join(("d", self.info['pattern']['KEY'], str(checksum), self.pyfile.name))
+ dl_link = urljoin(self.info['pattern']['HOST'], p_url)
+ return dl_link
getInfo = create_getInfo(ZippyshareCom)
diff --git a/module/plugins/internal/CaptchaService.py b/module/plugins/internal/CaptchaService.py
index d325d7928..965799e8e 100644
--- a/module/plugins/internal/CaptchaService.py
+++ b/module/plugins/internal/CaptchaService.py
@@ -1,95 +1,332 @@
# -*- coding: utf-8 -*-
import re
-from random import random
+from random import random
-class CaptchaService:
- __name__ = "CaptchaService"
- __version__ = "0.05"
+from module.common.json_layer import json_loads
- __description__ = """Captcha service plugin"""
- __author_name__ = "pyLoad Team"
- __author_mail__ = "admin@pyload.org"
+class CaptchaService:
+ __name__ = "CaptchaService"
+ __version__ = "0.16"
- def __init__(self, plugin):
- self.plugin = plugin
+ __description__ = """Base captcha service plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
-class ReCaptcha:
- RECAPTCHA_KEY_PATTERN = r"https?://(?:www\.)?google\.com/recaptcha/api/challenge\?k=(?P<key>\w+)"
- RECAPTCHA_KEY_AJAX_PATTERN = r"Recaptcha\.create\s*\(\s*[\"'](?P<key>\w+)[\"']\s*,"
+ KEY_PATTERN = None
- recaptcha_key = None
+ key = None #: last key detected
def __init__(self, plugin):
self.plugin = plugin
- def detect_key(self, html):
- m = re.search(self.RECAPTCHA_KEY_PATTERN, html)
- if m is None:
- m = re.search(self.RECAPTCHA_KEY_AJAX_PATTERN, html)
+
+ 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.fail(errmsg) #@TODO: replace all plugin.fail(errmsg) with plugin.error(errmsg) in 0.4.10
+ raise TypeError(errmsg)
+
+ m = re.search(self.KEY_PATTERN, html)
if m:
- self.recaptcha_key = m.group('key')
- return self.recaptcha_key
+ self.key = m.group(1).strip()
+ 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):
- if key is None and self.recaptcha_key:
- key = self.recaptcha_key
+ raise NotImplementedError
+
+
+ def result(self, server, challenge):
+ raise NotImplementedError
+
+
+class ReCaptcha(CaptchaService):
+ __name__ = "ReCaptcha"
+ __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:
- raise TypeError("ReCaptcha key not found")
+ self.plugin.logDebug("ReCaptcha key not found")
+ return None
- js = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={"k": key}, cookies=True)
+ 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 : '(.*?)',", js).group(1)
- server = re.search("server : '(.*?)',", js).group(1)
+ challenge = re.search("challenge : '(.+?)',", html).group(1)
+ server = re.search("server : '(.+?)',", html).group(1)
except:
- self.plugin.fail("recaptcha error")
- result = self.result(server, challenge)
+ errmsg = _("ReCaptcha challenge pattern not found")
+ self.plugin.fail(errmsg)
+ raise ValueError(errmsg)
+
+ self.plugin.logDebug("ReCaptcha challenge: %s" % challenge)
+
+ return challenge, self.result(server, challenge)
- return challenge, result
def result(self, server, challenge):
- return self.plugin.decryptCaptcha("%simage" % server, get={"c": challenge},
- cookies=True, forceUser=True, imgtype="jpg")
+ result = self.plugin.decryptCaptcha("%simage" % server,
+ get={'c': challenge},
+ cookies=True,
+ forceUser=True,
+ imgtype="jpg")
+
+ self.plugin.logDebug("ReCaptcha result: %s" % result)
+
+ return result
class AdsCaptcha(CaptchaService):
+ __name__ = "AdsCaptcha"
+ __version__ = "0.06"
- def challenge(self, src):
- js = self.plugin.req.load(src, cookies=True)
+ __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: '(.*?)',", js).group(1)
- server = re.search("server: '(.*?)',", js).group(1)
+ challenge = re.search("challenge: '(.+?)',", html).group(1)
+ server = re.search("server: '(.+?)',", html).group(1)
except:
- self.plugin.fail("adscaptcha error")
- result = self.result(server, challenge)
+ errmsg = _("AdsCaptcha challenge pattern not found")
+ self.plugin.fail(errmsg)
+ raise ValueError(errmsg)
+
+ self.plugin.logDebug("AdsCaptcha challenge: %s" % challenge)
+
+ return challenge, self.result(server, challenge)
- return challenge, result
def result(self, server, challenge):
- return self.plugin.decryptCaptcha("%sChallenge.aspx" % server, get={"cid": challenge, "dummy": random()},
- cookies=True, imgtype="jpg")
+ 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
class SolveMedia(CaptchaService):
+ __name__ = "SolveMedia"
+ __version__ = "0.06"
- def challenge(self, src):
- html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.noscript?k=%s" % src, cookies=True)
+ __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:
+ errmsg = _("SolveMedia challenge pattern not found")
+ self.plugin.fail(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
+
+
+class AdYouLike(CaptchaService):
+ __name__ = "AdYouLike"
+ __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:
- self.plugin.fail("solvemedia error")
- result = self.result(challenge)
+ errmsg = _("AdYouLike challenge pattern not found")
+ self.plugin.fail(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:
+ errmsg = _("AdYouLike result not found")
+ self.plugin.fail(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}
- return challenge, result
+ self.plugin.logDebug("AdYouLike result: %s" % result)
- def result(self, challenge):
- return self.plugin.decryptCaptcha("http://api.solvemedia.com/papi/media?c=%s" % challenge, imgtype="gif")
+ return result
diff --git a/module/plugins/internal/DeadCrypter.py b/module/plugins/internal/DeadCrypter.py
index d19731cb5..07c5c3881 100644
--- a/module/plugins/internal/DeadCrypter.py
+++ b/module/plugins/internal/DeadCrypter.py
@@ -1,19 +1,32 @@
# -*- coding: utf-8 -*-
+from urllib import unquote
+from urlparse import urlparse
+
+from module.plugins.internal.SimpleCrypter import create_getInfo
from module.plugins.Crypter import Crypter as _Crypter
class DeadCrypter(_Crypter):
- __name__ = "DeadCrypter"
- __version__ = "0.01"
- __type__ = "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")]
- __pattern__ = None
- __description__ = """Crypter is no longer available"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ @classmethod
+ def getInfo(cls, url="", html=""):
+ return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url}
def setup(self):
- self.fail("Crypter is no longer available")
+ 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
index a7cf1f3ea..6f3252f70 100644
--- a/module/plugins/internal/DeadHoster.py
+++ b/module/plugins/internal/DeadHoster.py
@@ -1,27 +1,32 @@
# -*- coding: utf-8 -*-
+from urllib import unquote
+from urlparse import urlparse
+
+from module.plugins.internal.SimpleHoster import create_getInfo
from module.plugins.Hoster import Hoster as _Hoster
-def create_getInfo(plugin):
+class DeadHoster(_Hoster):
+ __name__ = "DeadHoster"
+ __type__ = "hoster"
+ __version__ = "0.14"
- def getInfo(urls):
- yield [('#N/A: ' + url, 0, 1, url) for url in urls]
+ __pattern__ = r'^unmatchable$'
- return getInfo
+ __description__ = """ Hoster is no longer available """
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
-class DeadHoster(_Hoster):
- __name__ = "DeadHoster"
- __version__ = "0.11"
- __type__ = "hoster"
+ @classmethod
+ def getInfo(cls, url="", html=""):
+ return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url}
- __pattern__ = None
- __description__ = """Hoster is no longer available"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ def setup(self):
+ self.pyfile.error = "Hoster is no longer available"
+ self.offline() #@TODO: self.offline("Hoster is no longer available")
- def setup(self):
- self.fail("Hoster is no longer available")
+getInfo = create_getInfo(DeadHoster)
diff --git a/module/plugins/internal/AbstractExtractor.py b/module/plugins/internal/Extractor.py
index c7f54f847..0b2462dac 100644
--- a/module/plugins/internal/AbstractExtractor.py
+++ b/module/plugins/internal/Extractor.py
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
-
class ArchiveError(Exception):
pass
@@ -9,35 +8,52 @@ class CRCError(Exception):
pass
-class WrongPassword(Exception):
+class PasswordError(Exception):
pass
-class AbtractExtractor:
- __name__ = "AbtractExtractor"
- __version__ = "0.1"
+class Extractor:
+ __name__ = "Extractor"
+ __version__ = "0.13"
+
+ __description__ = """Base extractor plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "ranan@pyload.org"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
- __description__ = """Abtract extractor plugin"""
- __author_name__ = "pyLoad Team"
- __author_mail__ = "admin@pyload.org"
+ EXTENSIONS = []
- @staticmethod
- def checkDeps():
+
+ @classmethod
+ def checkDeps(cls):
""" Check if system statisfy dependencies
:return: boolean
"""
return True
- @staticmethod
- def getTargets(files_ids):
+
+ @classmethod
+ def isArchive(cls, file):
+ raise NotImplementedError
+
+
+ @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
"""
- raise NotImplementedError
+ targets = []
+
+ for file, id in files_ids:
+ if cls.isArchive(file):
+ targets.append((file, id))
+
+ return targets
- def __init__(self, m, file, out, fullpath, overwrite, excludefiles, renice):
+
+ def __init__(self, m, file, out, password, fullpath, overwrite, excludefiles, renice, delete, keepbroken):
"""Initialize extractor for specific file
:param m: ExtractArchive Hook plugin
@@ -47,49 +63,70 @@ class AbtractExtractor:
:param overwrite: Overwrite existing archives
:param renice: Renice value
"""
- self.m = m
- self.file = file
- self.out = out
- self.fullpath = fullpath
- self.overwrite = overwrite
+ self.m = m
+ self.file = file
+ self.out = out
+ self.password = password
+ self.fullpath = fullpath
+ self.overwrite = overwrite
self.excludefiles = excludefiles
- self.renice = renice
- self.files = [] #: Store extracted files here
+ self.renice = renice
+ self.delete = delete
+ self.keepbroken = keepbroken
+ self.files = [] #: Store extracted files here
+
def init(self):
""" Initialize additional data structures """
pass
- def checkArchive(self):
+
+ def verify(self):
"""Check if password if needed. Raise ArchiveError if integrity is
questionable.
- :return: boolean
:raises ArchiveError
"""
- return False
+ pass
+
- def checkPassword(self, password):
+ 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 True
+ if isinstance(password, basestring):
+ return True
+ else:
+ return False
+
+
+ def setPassword(self, password):
+ if self.isPassword(password):
+ self.password = password
+ return True
+ else:
+ return False
- def extract(self, progress, password=None):
+
+ def repair(self):
+ return False
+
+
+ def extract(self, progress=lambda x: 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 WrongPassword
+ :raises PasswordError
:raises CRCError
:raises ArchiveError
:return:
"""
raise NotImplementedError
+
def getDeleteFiles(self):
"""Return list of files to delete, do *not* delete them here.
@@ -97,6 +134,7 @@ class AbtractExtractor:
"""
raise NotImplementedError
+
def getExtractedFiles(self):
"""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
new file mode 100644
index 000000000..78de1ed0a
--- /dev/null
+++ b/module/plugins/internal/MultiHook.py
@@ -0,0 +1,218 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.Hook import Hook
+from module.utils import remove_chars
+
+
+class MultiHook(Hook):
+ __name__ = "MultiHook"
+ __type__ = "hook"
+ __version__ = "0.23"
+
+ __description__ = """Hook plugin for MultiHoster"""
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
+
+
+ interval = 12 * 60 * 60 #: reload hosters every 12h
+
+ HOSTER_REPLACEMENTS = [("1fichier.com" , "onefichier.com"),
+ ("2shared.com" , "twoshared.com" ),
+ ("4shared.com" , "fourshared.com"),
+ ("cloudnator.com" , "shragle.com" ),
+ ("easy-share.com" , "crocko.com" ),
+ ("fileparadox.com", "fileparadox.in"),
+ ("freakshare.net" , "freakshare.com"),
+ ("hellshare.com" , "hellshare.cz" ),
+ ("ifile.it" , "filecloud.io" ),
+ ("nowdownload.ch" , "nowdownload.sx"),
+ ("nowvideo.co" , "nowvideo.sx" ),
+ ("putlocker.com" , "firedrive.com" ),
+ ("share-rapid.cz" , "multishare.cz" ),
+ ("sharerapid.cz" , "multishare.cz" ),
+ ("ul.to" , "uploaded.to" ),
+ ("uploaded.net" , "uploaded.to" )]
+ HOSTER_EXCLUDED = []
+
+
+ def setup(self):
+ self.hosters = []
+ self.supported = []
+ self.new_supported = []
+
+
+ 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 getHosterCached(self):
+ if not self.hosters:
+ try:
+ hosterSet = self.toHosterSet(self.getHoster()) - set(self.HOSTER_EXCLUDED)
+ except Exception, e:
+ self.logError(e)
+ return []
+
+ try:
+ configMode = self.getConfig('hosterListMode', 'all')
+ if configMode in ("listed", "unlisted"):
+ configSet = self.toHosterSet(self.getConfig('hosterList', '').replace('|', ',').replace(';', ',').split(','))
+
+ if configMode == "listed":
+ hosterSet &= configSet
+ else:
+ hosterSet -= configSet
+
+ except Exception, e:
+ self.logError(e)
+
+ self.hosters = list(hosterSet)
+
+ return self.hosters
+
+
+ def toHosterSet(self, hosters):
+ hosters = set((str(x).strip().lower() for x in hosters))
+
+ for rep in self.HOSTER_REPLACEMENTS:
+ if rep[0] in hosters:
+ hosters.remove(rep[0])
+ hosters.add(rep[1])
+
+ hosters.discard('')
+ return hosters
+
+
+ def getHoster(self):
+ """Load list of supported hoster
+
+ :return: List of domain names
+ """
+ raise NotImplementedError
+
+
+ def coreReady(self):
+ if self.cb:
+ self.core.scheduler.removeJob(self.cb)
+
+ self.setConfig("activated", True) #: config not in sync after plugin reload
+
+ cfg_interval = self.getConfig("interval", None) #: reload interval in hours
+ if cfg_interval is not None:
+ self.interval = cfg_interval * 60 * 60
+
+ if self.interval:
+ self._periodical()
+ else:
+ self.periodical()
+
+
+ def initPeriodical(self):
+ pass
+
+
+ def periodical(self):
+ """reload hoster list periodically"""
+ self.logInfo(_("Reloading supported hoster list"))
+
+ old_supported = self.supported
+ self.supported = []
+ self.new_supported = []
+ self.hosters = []
+
+ self.overridePlugins()
+
+ old_supported = [hoster for hoster in old_supported if hoster not in self.supported]
+ if old_supported:
+ self.logDebug("Unload: %s" % ", ".join(old_supported))
+ for hoster in old_supported:
+ self.unloadHoster(hoster)
+
+
+ def overridePlugins(self):
+ 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]
+ excludedList = []
+
+ for hoster in self.getHosterCached():
+ name = remove_chars(hoster, "-.")
+
+ if name in accountList:
+ excludedList.append(hoster)
+ else:
+ if name in pluginMap:
+ self.supported.append(pluginMap[name])
+ else:
+ self.new_supported.append(hoster)
+
+ if not self.supported and not self.new_supported:
+ self.logError(_("No Hoster loaded"))
+ return
+
+ module = self.core.pluginManager.getPlugin(self.__name__)
+ klass = getattr(module, self.__name__)
+
+ # inject plugin plugin
+ self.logDebug("Overwritten Hosters: %s" % ", ".join(sorted(self.supported)))
+ for hoster in self.supported:
+ hdict = self.core.pluginManager.hosterPlugins[hoster]
+ hdict['new_module'] = module
+ hdict['new_name'] = self.__name__
+
+ if excludedList:
+ self.logInfo(_("Hosters not overwritten: %s" % ", ".join(sorted(excludedList))))
+
+ if self.new_supported:
+ hosters = sorted(self.new_supported)
+
+ self.logDebug("New Hosters: %s" % ", ".join(hosters))
+
+ # create new regexp
+ regexp = r'.*(%s).*' % "|".join([x.replace(".", "\.") for x in hosters])
+ if hasattr(klass, "__pattern__") and isinstance(klass.__pattern__, basestring) and '://' in klass.__pattern__:
+ regexp = r'%s|%s' % (klass.__pattern__, regexp)
+
+ self.logDebug("Regexp: %s" % regexp)
+
+ hdict = self.core.pluginManager.hosterPlugins[self.__name__]
+ hdict['pattern'] = regexp
+ hdict['re'] = re.compile(regexp)
+
+
+ def unloadHoster(self, hoster):
+ hdict = self.core.pluginManager.hosterPlugins[hoster]
+ 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 hosters. Scheduler job is removed by hookmanager"""
+ for hoster in self.supported:
+ self.unloadHoster(hoster)
+
+ # reset pattern
+ klass = getattr(self.core.pluginManager.getPlugin(self.__name__), self.__name__)
+ hdict = self.core.pluginManager.hosterPlugins[self.__name__]
+ hdict['pattern'] = getattr(klass, "__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.hasStatus("failed") and self.getConfig("unloadFailing", True):
+ hdict = self.core.pluginManager.hosterPlugins[pyfile.pluginname]
+ if "new_name" in hdict and hdict['new_name'] == self.__name__:
+ self.logDebug("Unload MultiHook", pyfile.pluginname, hdict)
+ self.unloadHoster(pyfile.pluginname)
+ pyfile.setStatus("queued")
diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py
index 46d943bd7..9d218c3b2 100644
--- a/module/plugins/internal/MultiHoster.py
+++ b/module/plugins/internal/MultiHoster.py
@@ -2,190 +2,79 @@
import re
-from module.utils import remove_chars
-from module.plugins.Hook import Hook
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns, set_cookies
-class MultiHoster(Hook):
- __name__ = "AbtractExtractor"
- __version__ = "0.19"
+class MultiHoster(SimpleHoster):
+ __name__ = "MultiHoster"
+ __type__ = "hoster"
+ __version__ = "0.26"
- __description__ = """Generic MultiHoster plugin"""
- __author_name__ = "pyLoad Team"
- __author_mail__ = "admin@pyload.org"
+ __pattern__ = r'^unmatchable$'
- replacements = [("2shared.com", "twoshared.com"), ("4shared.com", "fourshared.com"), ("cloudnator.com", "shragle.com"),
- ("ifile.it", "filecloud.io"), ("easy-share.com", "crocko.com"), ("freakshare.net", "freakshare.com"),
- ("hellshare.com", "hellshare.cz"), ("share-rapid.cz", "sharerapid.com"), ("sharerapid.cz", "sharerapid.com"),
- ("ul.to", "uploaded.to"), ("uploaded.net", "uploaded.to"), ("1fichier.com", "onefichier.com")]
- ignored = []
- interval = 24 * 60 * 60 #: reload hosters daily
+ __description__ = """Multi hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- def setup(self):
- self.hosters = []
- self.supported = []
- self.new_supported = []
-
- 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 getHosterCached(self):
- if not self.hosters:
-
- try:
- hosterSet = self.toHosterSet(self.getHoster()) - set(self.ignored)
- except Exception, e:
- self.logError("%s" % str(e))
- return []
-
- try:
- configMode = self.getConfig('hosterListMode', 'all')
- if configMode in ("listed", "unlisted"):
- configSet = self.toHosterSet(self.getConfig('hosterList', '').replace('|', ',').replace(';', ',').split(','))
-
- if configMode == "listed":
- hosterSet &= configSet
- else:
- hosterSet -= configSet
-
- except Exception, e:
- self.logError("%s" % str(e))
+ LOGIN_ACCOUNT = True
- self.hosters = list(hosterSet)
- return self.hosters
+ def setup(self):
+ self.chunkLimit = 1
+ self.multiDL = self.premium
- def toHosterSet(self, hosters):
- hosters = set((str(x).strip().lower() for x in hosters))
- for rep in self.replacements:
- if rep[0] in hosters:
- hosters.remove(rep[0])
- hosters.add(rep[1])
+ def prepare(self):
+ self.info = {}
+ self.link = "" #@TODO: Move to hoster class in 0.4.10
+ self.directDL = False #@TODO: Move to hoster class in 0.4.10
- hosters.discard('')
- return hosters
+ if self.LOGIN_ACCOUNT and not self.account:
+ self.fail(_("Required account not found"))
- def getHoster(self):
- """Load list of supported hoster
+ self.req.setOption("timeout", 120)
- :return: List of domain names
- """
- raise NotImplementedError
+ if isinstance(self.COOKIES, list):
+ set_cookies(self.req.cj, self.COOKIES)
- def coreReady(self):
- if self.cb:
- self.core.scheduler.removeJob(self.cb)
+ if self.DIRECT_LINK is None:
+ self.directDL = self.__pattern__ != r'^unmatchable$'
+ else:
+ self.directDL = self.DIRECT_LINK
- self.setConfig("activated", True) #: config not in sync after plugin reload
+ self.pyfile.url = replace_patterns(self.pyfile.url,
+ self.FILE_URL_REPLACEMENTS if hasattr(self, "FILE_URL_REPLACEMENTS") else self.URL_REPLACEMENTS) #@TODO: Remove FILE_URL_REPLACEMENTS check in 0.4.10
- cfg_interval = self.getConfig("interval", None) #: reload interval in hours
- if cfg_interval is not None:
- self.interval = cfg_interval * 60 * 60
- if self.interval:
- self._periodical()
- else:
- self.periodical()
+ def process(self, pyfile):
+ self.prepare()
- def initPeriodical(self):
- pass
+ if self.directDL:
+ self.logDebug("Looking for direct download link...")
+ self.handleDirect()
- def periodical(self):
- """reload hoster list periodically"""
- self.logInfo("Reloading supported hoster list")
+ if not self.link and not self.lastDownload:
+ self.preload()
- old_supported = self.supported
- self.supported, self.new_supported, self.hosters = [], [], []
+ if self.premium and (not self.CHECK_TRAFFIC or self.checkTrafficLeft()):
+ self.logDebug("Handled as premium download")
+ self.handlePremium()
- self.overridePlugins()
+ else:
+ self.logDebug("Handled as free download")
+ self.handleFree()
- old_supported = [hoster for hoster in old_supported if hoster not in self.supported]
- if old_supported:
- self.logDebug("UNLOAD: %s" % ", ".join(old_supported))
- for hoster in old_supported:
- self.unloadHoster(hoster)
+ self.downloadLink(self.link)
+ self.checkFile()
- def overridePlugins(self):
- pluginMap = {}
- for name in self.core.pluginManager.hosterPlugins.keys():
- pluginMap[name.lower()] = name
- accountList = [name.lower() for name, data in self.core.accountManager.accounts.items() if data]
- excludedList = []
+ def handlePremium(self):
+ return self.handleFree()
- for hoster in self.getHosterCached():
- name = remove_chars(hoster.lower(), "-.")
- if name in accountList:
- excludedList.append(hoster)
- else:
- if name in pluginMap:
- self.supported.append(pluginMap[name])
- else:
- self.new_supported.append(hoster)
-
- if not self.supported and not self.new_supported:
- self.logError(_("No Hoster loaded"))
- return
-
- module = self.core.pluginManager.getPlugin(self.__name__)
- klass = getattr(module, self.__name__)
-
- # inject plugin plugin
- self.logDebug("Overwritten Hosters: %s" % ", ".join(sorted(self.supported)))
- for hoster in self.supported:
- dict = self.core.pluginManager.hosterPlugins[hoster]
- dict['new_module'] = module
- dict['new_name'] = self.__name__
-
- if excludedList:
- self.logInfo("The following hosters were not overwritten - account exists: %s" % ", ".join(sorted(excludedList)))
-
- if self.new_supported:
- self.logDebug("New Hosters: %s" % ", ".join(sorted(self.new_supported)))
-
- # create new regexp
- regexp = r".*(%s).*" % "|".join([x.replace(".", "\\.") for x in self.new_supported])
- if hasattr(klass, "__pattern__") and isinstance(klass.__pattern__, basestring) and '://' in klass.__pattern__:
- regexp = r"%s|%s" % (klass.__pattern__, regexp)
-
- self.logDebug("Regexp: %s" % regexp)
-
- dict = self.core.pluginManager.hosterPlugins[self.__name__]
- dict['pattern'] = regexp
- dict['re'] = re.compile(regexp)
-
- def unloadHoster(self, hoster):
- dict = self.core.pluginManager.hosterPlugins[hoster]
- if "module" in dict:
- del dict['module']
-
- if "new_module" in dict:
- del dict['new_module']
- del dict['new_name']
-
- def unload(self):
- """Remove override for all hosters. Scheduler job is removed by hookmanager"""
- for hoster in self.supported:
- self.unloadHoster(hoster)
-
- # reset pattern
- klass = getattr(self.core.pluginManager.getPlugin(self.__name__), self.__name__)
- dict = self.core.pluginManager.hosterPlugins[self.__name__]
- dict['pattern'] = getattr(klass, "__pattern__", r'^unmatchable$')
- dict['re'] = re.compile(dict['pattern'])
-
- def downloadFailed(self, pyfile):
- """remove plugin override if download fails but not if file is offline/temp.offline"""
- if pyfile.hasStatus("failed") and self.getConfig("unloadFailing", True):
- hdict = self.core.pluginManager.hosterPlugins[pyfile.pluginname]
- if "new_name" in hdict and hdict['new_name'] == self.__name__:
- self.logDebug("Unload MultiHoster", pyfile.pluginname, hdict)
- self.unloadHoster(pyfile.pluginname)
- pyfile.setStatus("queued")
+ def handleFree(self):
+ if self.premium:
+ raise NotImplementedError
+ else:
+ self.fail(_("Required premium account not found"))
diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py
index dc93bef4d..428826456 100644
--- a/module/plugins/internal/SimpleCrypter.py
+++ b/module/plugins/internal/SimpleCrypter.py
@@ -2,80 +2,141 @@
import re
+from urlparse import urlparse
+
from module.plugins.Crypter import Crypter
-from module.utils import html_unescape
-from module.plugins.internal.SimpleHoster import PluginParseError, replace_patterns, set_cookies
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns, set_cookies
+from module.utils import fixup
-class SimpleCrypter(Crypter):
- __name__ = "SimpleCrypter"
- __version__ = "0.10"
- __type__ = "crypter"
+class SimpleCrypter(Crypter, SimpleHoster):
+ __name__ = "SimpleCrypter"
+ __type__ = "crypter"
+ __version__ = "0.35"
- __pattern__ = None
+ __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"""
- __author_name__ = ("stickell", "zoidberg", "Walter Purcaro")
- __author_mail__ = ("l.stickell@yahoo.it", "zoidberg@mujmail.cz", "vuolter@gmail.com")
+ __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: group(1) must be a download link or a regex to catch more links
- example: LINK_PATTERN = r'<div class="link"><a href="(http://speedload.org/\w+)'
+ LINK_PATTERN: Download link or regex to catch links in group(1)
+ example: LINK_PATTERN = r'<div class="link"><a href="(.+?)"'
- TITLE_PATTERN: (optional) The group defined by 'title' should be the title
- example: TITLE_PATTERN = r'<title>Files of: (?P<title>[^<]+) folder</title>'
+ 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 file is yet available online
+ OFFLINE_PATTERN: (optional) Checks if the page is unreachable
example: OFFLINE_PATTERN = r'File (deleted|not found)'
- TEMP_OFFLINE_PATTERN: (optional) Checks if the file is temporarily offline
+ TEMP_OFFLINE_PATTERN: (optional) Checks if the page is temporarily unreachable
example: TEMP_OFFLINE_PATTERN = r'Server maintainance'
- If it's impossible to extract the links using the LINK_PATTERN only you can override the getLinks method.
+ 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:
- If the links are disposed on multiple pages you need to define a pattern:
+ PAGES_PATTERN: (optional) group(1) should be the number of overall pages containing the links
+ example: PAGES_PATTERN = r'Pages: (\d+)'
- PAGES_PATTERN: The group defined by 'pages' must be the total number of pages
- example: PAGES_PATTERN = r'Pages: (?P<pages>\d+)'
+ and its loadPage method:
- and a function:
- loadPage(self, page_n):
- return the html of the page number 'page_n'
+ def loadPage(self, page_n):
+ return the html of the page number page_n
"""
- URL_REPLACEMENTS = []
+ 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
+
+
+ #@TODO: Remove in 0.4.10
+ def init(self):
+ account_name = (self.__name__ + ".py").replace("Folder.py", "").replace(".py", "")
+ account = self.core.accountManager.getAccountPlugin(account_name)
+
+ if account and account.canUse():
+ self.user, data = account.selectAccount()
+ self.req = account.getAccountRequest(self.user)
+ self.premium = account.isPremium(self.user)
+
+ self.account = account
+
+
+ def prepare(self):
+ self.info = {}
+ self.links = [] #@TODO: Move to hoster class in 0.4.10
- SH_COOKIES = True # or False or list of tuples [(domain, name, value)]
+ 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 setup(self):
- if isinstance(self.SH_COOKIES, list):
- set_cookies(self.req.cj, self.SH_COOKIES)
def decrypt(self, pyfile):
- pyfile.url = replace_patterns(pyfile.url, self.URL_REPLACEMENTS)
+ self.prepare()
- self.html = self.load(pyfile.url, decode=True)
+ self.preload()
- self.checkOnline()
+ if self.html is None:
+ self.fail(_("No html retrieved"))
- package_name, folder_name = self.getPackageNameAndFolder()
+ self.checkInfo()
- self.package_links = self.getLinks()
+ self.links = self.getLinks()
if hasattr(self, 'PAGES_PATTERN') and hasattr(self, 'loadPage'):
self.handleMultiPages()
- self.logDebug('Package has %d links' % len(self.package_links))
+ self.logDebug("Package has %d links" % len(self.links))
+
+ if self.links:
+ self.packages = [(self.info['name'], self.links, self.info['folder'])]
+
+
+ def checkNameSize(self, getinfo=True):
+ if getinfo:
+ self.updateInfo(self.getInfo(self.pyfile.url, self.html))
- if self.package_links:
- self.packages = [(package_name, self.package_links, folder_name)]
+ name = self.info['name']
+ url = self.info['url']
+
+ if name and name != url:
+ self.pyfile.name = name
else:
- self.fail('Could not extract any links')
+ self.pyfile.name = self.info['name'] = urlparse(name).path.split('/')[-1]
+
+ folder = self.info['folder'] = self.pyfile.name
+
+ self.logDebug("File name: %s" % self.pyfile.name,
+ "File folder: %s" % folder)
+
def getLinks(self):
"""
@@ -84,35 +145,14 @@ class SimpleCrypter(Crypter):
"""
return re.findall(self.LINK_PATTERN, self.html)
- def checkOnline(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 getPackageNameAndFolder(self):
- if hasattr(self, 'TITLE_PATTERN'):
- m = re.search(self.TITLE_PATTERN, self.html)
- if m:
- name = folder = html_unescape(m.group('title').strip())
- self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder))
- return name, folder
-
- name = self.pyfile.package().name
- folder = self.pyfile.package().folder
- self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder))
- return name, folder
def handleMultiPages(self):
- pages = re.search(self.PAGES_PATTERN, self.html)
- if pages:
- pages = int(pages.group('pages'))
- else:
+ try:
+ m = re.search(self.PAGES_PATTERN, self.html)
+ pages = int(m.group(1))
+ except:
pages = 1
for p in xrange(2, pages + 1):
self.html = self.loadPage(p)
- self.package_links += self.getLinks()
-
- def parseError(self, msg):
- raise PluginParseError(msg)
+ self.links += self.getLinks()
diff --git a/module/plugins/internal/SimpleDereferer.py b/module/plugins/internal/SimpleDereferer.py
new file mode 100644
index 000000000..0ad1098f4
--- /dev/null
+++ b/module/plugins/internal/SimpleDereferer.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from urllib import unquote
+
+from module.plugins.Crypter import Crypter
+from module.plugins.internal.SimpleHoster import _isDirectLink, set_cookies
+
+
+class SimpleDereferer(Crypter):
+ __name__ = "SimpleDereferer"
+ __type__ = "crypter"
+ __version__ = "0.01"
+
+ __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 = _isDirectLink(pyfile.url)
+
+ if not link:
+ try:
+ link = unquote(re.match(self.__pattern__, pyfile.url).group('LINK'))
+
+ except Exception:
+ self.prepare()
+ self.preload()
+
+ if self.html is None:
+ self.fail(_("No html retrieved"))
+
+ self.checkStatus()
+
+ link = self.getLink()
+
+ if link.strip():
+ self.urls = [link.strip()] #@TODO: Remove `.strip()` in 0.4.10
+
+
+ def prepare(self):
+ 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
index 0dfecf0fb..d9732d063 100644
--- a/module/plugins/internal/SimpleHoster.py
+++ b/module/plugins/internal/SimpleHoster.py
@@ -1,34 +1,51 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-from urlparse import urlparse
import re
+
+from os.path import exists
from time import time
+from urllib import unquote
+from urlparse import urljoin, urlparse
-from module.plugins.Hoster import Hoster
-from module.utils import html_unescape, fixup, parseFileSize
-from module.network.RequestFactory import getURL
+from module.PyFile import statusMap as _statusMap
from module.network.CookieJar import CookieJar
+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)
- #self.logDebug(rf, rt, string)
return string
@@ -44,12 +61,13 @@ def parseHtmlTagAttrValue(attr_name, tag):
return m.group(2) if m else None
-def parseHtmlForm(attr_str, html, input_names=None):
- for form in re.finditer(r"(?P<tag><form[^>]*%s[^>]*>)(?P<content>.*?)</?(form|body|html)[^>]*>" % attr_str,
+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):
+ 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))
@@ -58,9 +76,9 @@ def parseHtmlForm(attr_str, html, input_names=None):
else:
inputs[name] = value
- if isinstance(input_names, dict):
+ if input_names:
# check input attributes
- for key, val in input_names.items():
+ for key, val in input_names.iteritems():
if key in inputs:
if isinstance(val, basestring) and inputs[key] == val:
continue
@@ -68,238 +86,535 @@ def parseHtmlForm(attr_str, html, input_names=None):
continue
elif hasattr(val, "search") and re.match(val, inputs[key]):
continue
- break # attibute value does not match
+ break #: attibute value does not match
else:
- break # attibute name does not match
+ break #: attibute name does not match
else:
- return action, inputs # passed attribute check
+ return action, inputs #: passed attribute check
else:
# no attribute check
return action, inputs
- return {}, None # no matching form found
+ return {}, None #: no matching form found
-def parseFileInfo(self, url='', html=''):
- info = {"name": url, "size": 0, "status": 3}
+#: 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:
+ res = urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 0, 3, url
+
+ return res
- if hasattr(self, "pyfile"):
- url = self.pyfile.url
- if hasattr(self, "req") and self.req.http.code == '404':
- info['status'] = 1
+#@TODO: Remove in 0.4.10
+#@NOTE: Every plugin must have own parseInfos classmethod to work with 0.4.10
+def create_getInfo(plugin):
+ if hasattr(plugin, "parseInfos"):
+ fn = lambda urls: [(info['name'], info['size'], info['status'], info['url']) for info in plugin.parseInfos(urls)]
else:
- if not html and hasattr(self, "html"):
- html = self.html
- if isinstance(self.SH_BROKEN_ENCODING, (str, unicode)):
- html = unicode(html, self.SH_BROKEN_ENCODING)
- if hasattr(self, "html"):
- self.html = html
-
- if (hasattr(self, "OFFLINE_PATTERN") and re.search(self.OFFLINE_PATTERN, html)) or \
- (hasattr(self, "FILE_OFFLINE_PATTERN") and re.search(self.FILE_OFFLINE_PATTERN, html)):
- # File offline
- info['status'] = 1
- else:
- online = False
- try:
- info.update(re.match(self.__pattern__, url).groupdict())
- except:
- pass
+ fn = lambda urls: [parseFileInfo(url) for url in urls]
- for pattern in ("FILE_INFO_PATTERN", "FILE_NAME_PATTERN", "FILE_SIZE_PATTERN"):
- try:
- info.update(re.search(getattr(self, pattern), html).groupdict())
- online = True
- except AttributeError:
- continue
+ return fn
- if online:
- # File online, return name and size
- info['status'] = 2
- if 'N' in info:
- info['name'] = replace_patterns(info['N'], self.FILE_NAME_REPLACEMENTS)
- if 'S' in info:
- size = replace_patterns(info['S'] + info['U'] if 'U' in info else info['S'],
- self.FILE_SIZE_REPLACEMENTS)
- info['size'] = parseFileSize(size)
- elif isinstance(info['size'], (str, unicode)):
- if 'units' in info:
- info['size'] += info['units']
- info['size'] = parseFileSize(info['size'])
- if hasattr(self, "file_info"):
- self.file_info = info
+def timestamp():
+ return int(time() * 1000)
- return info['name'], info['size'], info['status'], url
+#@TODO: Move to hoster class in 0.4.10
+def _isDirectLink(self, url, resumable=False):
+ link = ""
-def create_getInfo(plugin):
+ for i in xrange(5 if resumable else 1):
+ header = self.load(url, ref=True, cookies=True, just_header=True, decode=True)
- def getInfo(urls):
- for url in urls:
- cj = CookieJar(plugin.__name__)
- if isinstance(plugin.SH_COOKIES, list):
- set_cookies(cj, plugin.SH_COOKIES)
- file_info = parseFileInfo(plugin, url, getURL(replace_patterns(url, plugin.FILE_URL_REPLACEMENTS),
- decode=not plugin.SH_BROKEN_ENCODING, cookies=cj))
- yield file_info
+ if 'content-disposition' in header or 'content-length' in header:
+ link = url
- return getInfo
+ elif 'location' in header and header['location']:
+ location = header['location']
+ if not urlparse(location).scheme:
+ p = urlparse(url)
+ base = "%s://%s" % (p.scheme, p.netloc)
+ location = urljoin(base, location)
-def timestamp():
- return int(time() * 1000)
+ if 'code' in header and header['code'] == 302:
+ link = location
+
+ elif resumable:
+ url = location
+ self.logDebug("Redirect #%d to: %s" % (++i, location))
+ continue
+
+ elif 'content-type' in header and header['content-type' ] and "html" not in header['content-type']:
+ link = url
+
+ break
+ else:
+ self.logError(_("Too many redirects"))
+ return link
-class PluginParseError(Exception):
- def __init__(self, msg):
- Exception.__init__(self)
- self.value = 'Parse error (%s) - plugin may be out of date' % msg
+def secondsToMidnight(gmt=0):
+ now = datetime.utcnow() + timedelta(hours=gmt)
- def __str__(self):
- return repr(self.value)
+ 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"
- __version__ = "0.34"
- __type__ = "hoster"
+ __name__ = "SimpleHoster"
+ __type__ = "hoster"
+ __version__ = "0.82"
- __pattern__ = None
+ __pattern__ = r'^unmatchable$'
__description__ = """Simple hoster plugin"""
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
"""
- Following patterns should be defined by each hoster:
+ Info patterns should be defined by each hoster:
- FILE_INFO_PATTERN: Name and Size of the file
- example: FILE_INFO_PATTERN = r'(?P<N>file_name) (?P<S>file_size) (?P<U>size_unit)'
+ 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
- FILE_NAME_PATTERN: Name that will be set for the file
- example: FILE_NAME_PATTERN = r'(?P<N>file_name)'
- FILE_SIZE_PATTERN: Size that will be checked for the file
- example: FILE_SIZE_PATTERN = r'(?P<S>file_size) (?P<U>size_unit)'
+ 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)'
- OFFLINE_PATTERN: Checks if the file is yet available online
+ 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)'
- or:
- FILE_OFFLINE_PATTERN: Deprecated
- TEMP_OFFLINE_PATTERN: Checks if the file is temporarily offline
- example: TEMP_OFFLINE_PATTERN = r'Server maintainance'
+ 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:
- PREMIUM_ONLY_PATTERN: (optional) Checks if the file can be downloaded only with a premium account
+ 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="(.+?)"'
"""
- FILE_NAME_REPLACEMENTS = [("&#?\w+;", fixup)]
- FILE_SIZE_REPLACEMENTS = []
- FILE_URL_REPLACEMENTS = []
+ 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)
+
+
+ @classmethod
+ def parseInfos(cls, urls):
+ for url in urls:
+ url = replace_patterns(url, cls.FILE_URL_REPLACEMENTS if hasattr(cls, "FILE_URL_REPLACEMENTS") else cls.URL_REPLACEMENTS) #@TODO: Remove FILE_URL_REPLACEMENTS check in 0.4.10
+ yield cls.getInfo(url)
+
+
+ @classmethod
+ def getInfo(cls, url="", html=""):
+ info = {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3, 'url': url}
+ online = False
+
+ try:
+ info['pattern'] = re.match(cls.__pattern__, url).groupdict() #: pattern groups will be saved here, please save api stuff to info['api']
+ except Exception:
+ pass
+
+ if not html:
+ try:
+ if not url:
+ info['error'] = "missing url"
+ info['status'] = 1
+ raise
+
+ if _isDirectLink(url):
+ info['error'] = "direct link"
+ info['status'] = 2
+ raise
+
+ 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
+ raise
+
+ if e.code is 503:
+ info['status'] = 6
+ raise
+ except:
+ return info
+
+ if hasattr(cls, "OFFLINE_PATTERN") and re.search(cls.OFFLINE_PATTERN, html):
+ info['status'] = 1
+
+ elif hasattr(cls, "FILE_OFFLINE_PATTERN") and re.search(cls.FILE_OFFLINE_PATTERN, html): #@TODO: Remove in 0.4.10
+ info['status'] = 1
+
+ elif hasattr(cls, "TEMP_OFFLINE_PATTERN") and re.search(cls.TEMP_OFFLINE_PATTERN, html):
+ info['status'] = 6
+
+ else:
+ if not 'pattern' in info:
+ info['pattern'] = {}
+
+ for pattern in ("FILE_INFO_PATTERN", "INFO_PATTERN",
+ "FILE_NAME_PATTERN", "NAME_PATTERN",
+ "FILE_SIZE_PATTERN", "SIZE_PATTERN",
+ "HASHSUM_PATTERN"): #@TODO: Remove old patterns starting with "FILE_" in 0.4.10
+ 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 not info['pattern']:
+ info.pop('pattern', None)
+
+ if online:
+ info['status'] = 2
+
+ if 'N' in info['pattern']:
+ info['name'] = replace_patterns(unquote(info['pattern']['N'].strip()),
+ cls.FILE_NAME_REPLACEMENTS if hasattr(cls, "FILE_NAME_REPLACEMENTS") else cls.NAME_REPLACEMENTS) #@TODO: Remove FILE_NAME_REPLACEMENTS check in 0.4.10
+
+ if 'S' in info['pattern']:
+ size = replace_patterns(info['pattern']['S'] + info['pattern']['U'] if 'U' in info['pattern'] else info['pattern']['S'],
+ cls.FILE_SIZE_REPLACEMENTS if hasattr(cls, "FILE_SIZE_REPLACEMENTS") else cls.SIZE_REPLACEMENTS) #@TODO: Remove FILE_SIZE_REPLACEMENTS check in 0.4.10
+ info['size'] = parseFileSize(size)
+
+ elif isinstance(info['size'], basestring):
+ unit = info['units'] if 'units' in info else None
+ info['size'] = parseFileSize(info['size'], unit)
- SH_BROKEN_ENCODING = False # Set to True or encoding name if encoding in http header is not correct
- SH_COOKIES = True # or False or list of tuples [(domain, name, value)]
- SH_CHECK_TRAFFIC = False # True = force check traffic left for a premium account
+ if 'H' in info['pattern']:
+ hashtype = info['pattern']['T'] if 'T' in info['pattern'] else "hash"
+ info[hashtype] = info['pattern']['H']
+ return info
- def init(self):
- self.file_info = {}
def setup(self):
self.resumeDownload = self.multiDL = self.premium
- if isinstance(self.SH_COOKIES, list):
- set_cookies(self.req.cj, self.SH_COOKIES)
- def process(self, pyfile):
- pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS)
+
+ def prepare(self):
+ self.info = {}
+ 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
+
self.req.setOption("timeout", 120)
- # Due to a 0.4.9 core bug self.load would keep previous cookies even if overridden by cookies parameter.
- # Workaround using getURL. Can be reverted in 0.5 as the cookies bug has been fixed.
- self.html = getURL(pyfile.url, decode=not self.SH_BROKEN_ENCODING, cookies=self.SH_COOKIES)
- premium_only = hasattr(self, 'PREMIUM_ONLY_PATTERN') and re.search(self.PREMIUM_ONLY_PATTERN, self.html)
- if not premium_only: # Usually premium only pages doesn't show the file information
- self.getFileInfo()
-
- if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()):
- self.handlePremium()
- elif premium_only:
- self.fail("This link require a premium account")
+
+ 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:
- # This line is required due to the getURL workaround. Can be removed in 0.5
- self.html = self.load(pyfile.url, decode=not self.SH_BROKEN_ENCODING, cookies=self.SH_COOKIES)
- self.handleFree()
+ self.directDL = self.DIRECT_LINK
- def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=False):
- if type(url) == unicode:
- url = url.encode('utf8')
- return Hoster.load(self, url=url, get=get, post=post, ref=ref, cookies=cookies,
- just_header=just_header, decode=decode)
+ self.pyfile.url = replace_patterns(self.pyfile.url,
+ self.FILE_URL_REPLACEMENTS if hasattr(self, "FILE_URL_REPLACEMENTS") else self.URL_REPLACEMENTS) #@TODO: Remove FILE_URL_REPLACEMENTS check in 0.4.10
- def getFileInfo(self):
- self.logDebug("URL: %s" % self.pyfile.url)
- if hasattr(self, "TEMP_OFFLINE_PATTERN") and re.search(self.TEMP_OFFLINE_PATTERN, self.html):
- self.tempOffline()
- name, size, status = parseFileInfo(self)[:3]
+ 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()
+
+ if self.multihost and not self.link and not self.lastDownload:
+ self.logDebug("Looking for leeched download link...")
+ self.handleMulti()
+
+ 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.html is None:
+ self.fail(_("No html retrieved"))
+
+ if self.premium and (not self.CHECK_TRAFFIC or self.checkTrafficLeft()):
+ self.logDebug("Handled as premium download")
+ self.handlePremium()
+
+ else:
+ self.logDebug("Handled as free download")
+ self.handleFree()
+
+ self.downloadLink(self.link)
+ self.checkFile()
+
+
+ def downloadLink(self, link):
+ if link and isinstance(link, basestring):
+ self.correctCaptcha()
+ self.download(link, disposition=True)
+
+
+ def checkFile(self):
+ if self.cTask and not self.lastDownload:
+ self.invalidCaptcha()
+ self.retry(10, reason=_("Wrong captcha"))
+
+ elif not self.lastDownload or not exists(fs_encode(self.lastDownload)):
+ errmsg = _("No file downloaded")
+ if 'error' in self.info:
+ self.fail(errmsg, self.info['error'])
+ else:
+ self.fail(errmsg)
+
+ else:
+ rules = {'empty file': re.compile(r"^$")}
+
+ 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() + (" | " + self.lastCheck.strip() if self.lastCheck else "")
+ self.retry(10, 60, errmsg)
+
+
+ def checkErrors(self):
+ if hasattr(self, 'PREMIUM_ONLY_PATTERN') and self.premium and re.search(self.PREMIUM_ONLY_PATTERN, self.html):
+ self.fail(_("Link require a premium account to be handled"))
+
+ if hasattr(self, 'ERROR_PATTERN'):
+ m = re.search(self.ERROR_PATTERN, self.html)
+ if m:
+ errmsg = self.info['error'] = m.group(1)
+ self.error(errmsg)
+
+ if 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)
- if status == 1:
+
+ def checkStatus(self, getinfo=True):
+ if getinfo:
+ self.updateInfo(self.getInfo(self.pyfile.url, self.html))
+
+ status = self.info['status']
+
+ if status is 1:
self.offline()
- elif status != 2:
- self.logDebug(self.file_info)
- self.parseError('File info')
- if name:
+ elif status is 6:
+ self.tempOffline()
+
+ elif status is not 2:
+ self.logDebug("File status: %s" % statusMap[status],
+ "File info: %s" % self.info)
+
+
+ def checkNameSize(self, getinfo=True):
+ if getinfo:
+ self.updateInfo(self.getInfo(self.pyfile.url, self.html))
+
+ name = self.info['name']
+ size = self.info['size']
+ url = self.info['url']
+
+ if name and name != url:
self.pyfile.name = name
else:
- self.pyfile.name = html_unescape(urlparse(self.pyfile.url).path.split("/")[-1])
+ self.pyfile.name = name = self.info['name'] = urlparse(name).path.split('/')[-1]
- if size:
+ if size > 0:
self.pyfile.size = size
else:
- self.logError("File size not parsed")
+ size = "Unknown"
+
+ self.logDebug("File name: %s" % name,
+ "File size: %s" % size)
+
+
+ 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 updateInfo(self, info):
+ self.logDebug(_("File info (BEFORE): %s") % self.info)
+ self.info.update(info)
+ self.logDebug(_("File info (AFTER): %s") % self.info)
+
+
+ def handleDirect(self):
+ link = _isDirectLink(self, self.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): #: Multi-hoster handler
+ pass
- self.logDebug("FILE NAME: %s FILE SIZE: %s" % (self.pyfile.name, self.pyfile.size))
- return self.file_info
def handleFree(self):
- self.fail("Free download not implemented")
+ if not hasattr(self, 'LINK_FREE_PATTERN'):
+ self.fail(_("Free download not implemented"))
+
+ try:
+ 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)
+
+ except Exception, e:
+ self.fail(e)
+
def handlePremium(self):
- self.fail("Premium download not implemented")
+ if not hasattr(self, 'LINK_PREMIUM_PATTERN'):
+ self.fail(_("Premium download not implemented"))
+
+ try:
+ m = re.search(self.LINK_PREMIUM_PATTERN, self.html)
+ if m is None:
+ self.error(_("Premium download link not found"))
+
+ self.link = m.group(1)
+
+ except Exception, e:
+ self.fail(e)
- def parseError(self, msg):
- raise PluginParseError(msg)
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)
+ time_str = "%dh %dm" % divmod(wait_time / 60, 60)
else:
wait_time = 900
- time_str = "(unknown time)"
+ time_str = _("(unknown time)")
max_tries = 100
- self.logInfo("Download limit reached, reconnect or wait %s" % time_str)
+ self.logInfo(_("Download limit reached, reconnect or wait %s") % time_str)
self.setWait(wait_time, True)
self.wait()
- self.retry(max_tries=max_tries, reason="Download limit reached")
+ self.retry(max_tries=max_tries, reason=_("Download limit reached"))
+
- def parseHtmlForm(self, attr_str='', input_names=None):
+ def parseHtmlForm(self, attr_str="", input_names={}):
return parseHtmlForm(attr_str, self.html, input_names)
+
def checkTrafficLeft(self):
traffic = self.account.getAccountInfo(self.user, True)['trafficleft']
- if traffic == -1:
+
+ if traffic is None:
+ return False
+ elif traffic == -1:
return True
- 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.5
- def wait(self, seconds=False, reconnect=False):
- if seconds:
- self.setWait(seconds, reconnect)
- super(SimpleHoster, self).wait()
+ 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
index 0251620ab..572fe95b9 100644
--- a/module/plugins/internal/UnRar.py
+++ b/module/plugins/internal/UnRar.py
@@ -1,135 +1,163 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
import os
import re
-from os.path import join
+
from glob import glob
-from subprocess import Popen, PIPE
+from os.path import basename, dirname, join
from string import digits
+from subprocess import Popen, PIPE
+from module.plugins.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError
from module.utils import save_join, decode
-from module.plugins.internal.AbstractExtractor import AbtractExtractor, WrongPassword, ArchiveError, CRCError
-class UnRar(AbtractExtractor):
- __name__ = "UnRar"
- __version__ = "0.16"
+def renice(pid, value):
+ if os.name != "nt" and value:
+ try:
+ Popen(["renice", str(value), str(pid)], stdout=PIPE, stderr=PIPE, bufsize=-1)
+ except:
+ print "Renice failed"
+
+
+class UnRar(Extractor):
+ __name__ = "UnRar"
+ __version__ = "1.01"
__description__ = """Rar extractor plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
-
- # there are some more uncovered rar formats
- re_version = re.compile(r"(UNRAR 5[\.\d]+(.*?)freeware)")
- re_splitfile = re.compile(r"(.*)\.part(\d+)\.rar$", re.I)
- re_partfiles = re.compile(r".*\.(rar|r[0-9]+)", re.I)
- re_filelist = re.compile(r"(.+)\s+(\d+)\s+(\d+)\s+")
- re_filelist5 = re.compile(r"(.+)\s+(\d+)\s+\d\d-\d\d-\d\d\s+\d\d:\d\d\s+(.+)")
- re_wrongpwd = re.compile("(Corrupt file or wrong password|password incorrect)", re.I)
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
CMD = "unrar"
+ EXTENSIONS = ["rar", "zip", "cab", "arj", "lzh", "tar", "gz", "bz2", "ace", "uue", "jar", "iso", "7z", "xz", "z"]
+
+
+ #@NOTE: there are some more uncovered rar formats
+ re_rarpart = re.compile(r'(.*)\.part(\d+)\.rar$', re.I)
+ re_rarfile = re.compile(r'.*\.(rar|r\d+)$', re.I)
+
+ re_filelist = re.compile(r'(.+)\s+(\d+)\s+(\d+)\s+|(.+)\s+(\d+)\s+\d\d-\d\d-\d\d\s+\d\d:\d\d\s+(.+)')
+ re_wrongpwd = re.compile(r'password', re.I)
+ re_wrongcrc = re.compile(r'encrypted|damaged|CRC failed|checksum error', re.I)
- @staticmethod
- def checkDeps():
+
+ @classmethod
+ def checkDeps(cls):
if os.name == "nt":
- UnRar.CMD = join(pypath, "UnRAR.exe")
- p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE)
+ cls.CMD = join(pypath, "UnRAR.exe")
+ p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE)
p.communicate()
else:
try:
- p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE)
+ p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE)
p.communicate()
- except OSError:
+ except OSError:
# fallback to rar
- UnRar.CMD = "rar"
- p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE)
+ cls.CMD = "rar"
+ p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE)
p.communicate()
return True
- @staticmethod
- def getTargets(files_ids):
- result = []
+
+ @classmethod
+ def isArchive(cls, file):
+ f = basename(file).lower()
+ return any(f.endswith('.%s' % ext) for ext in cls.EXTENSIONS)
+
+
+ @classmethod
+ def getTargets(cls, files_ids):
+ targets = []
for file, id in files_ids:
- if not file.endswith(".rar"):
+ if not cls.isArchive(file):
continue
- match = UnRar.re_splitfile.findall(file)
- if match:
+ m = cls.re_rarpart.findall(file)
+ if m:
# only add first parts
- if int(match[0][1]) == 1:
- result.append((file, id))
+ if int(m[0][1]) == 1:
+ targets.append((file, id))
else:
- result.append((file, id))
+ targets.append((file, id))
- return result
+ return targets
- def init(self):
- self.passwordProtected = False
- self.headerProtected = False #: list files will not work without password
- self.smallestFile = None #: small file to test passwords
- self.password = "" #: save the correct password
- def checkArchive(self):
- p = self.call_unrar("l", "-v", self.file)
- out, err = p.communicate()
- if self.re_wrongpwd.search(err):
- self.passwordProtected = True
- self.headerProtected = True
- return True
+ def check(self, out="", err=""):
+ if not out or not err:
+ return
+
+ if err.strip():
+ if self.re_wrongpwd.search(err):
+ raise PasswordError
+
+ elif self.re_wrongcrc.search(err):
+ raise CRCError
+
+ else: #: raise error if anything is on stderr
+ raise ArchiveError(err.strip())
# output only used to check if passworded files are present
- if self.re_version.search(out):
- for attr, size, name in self.re_filelist5.findall(out):
- if attr.startswith("*"):
- self.passwordProtected = True
- return True
- else:
- for name, size, packed in self.re_filelist.findall(out):
- if name.startswith("*"):
- self.passwordProtected = True
- return True
+ for attr in self.re_filelist.findall(out):
+ if attr[0].startswith("*"):
+ raise PasswordError
+
+
+ def verify(self):
+ p = self.call_cmd("l", "-v", self.file, password=self.password)
+
+ self.check(*p.communicate())
+
+ if p and p.returncode:
+ raise ArchiveError("Process terminated")
+
+ if not self.list():
+ raise ArchiveError("Empty archive")
- self.listContent()
- if not self.files:
- raise ArchiveError("Empty Archive")
+
+ def isPassword(self, password):
+ if isinstance(password, basestring):
+ p = self.call_cmd("l", "-v", self.file, password=password)
+ out, err = p.communicate()
+
+ if not self.re_wrongpwd.search(err):
+ return True
return False
- def checkPassword(self, password):
- # at this point we can only verify header protected files
- if self.headerProtected:
- p = self.call_unrar("l", "-v", self.file, password=password)
+
+ def repair(self):
+ p = self.call_cmd("rc", self.file)
+ out, err = p.communicate()
+
+ if p.returncode or err.strip():
+ p = self.call_cmd("r", self.file)
out, err = p.communicate()
- if self.re_wrongpwd.search(err):
+
+ if p.returncode or err.strip():
return False
+ else:
+ self.file = join(dirname(self.file), re.search(r'(fixed|rebuild)\.%s' % basename(self.file), out).group(0))
return True
- def extract(self, progress, password=None):
+
+ def extract(self, progress=lambda x: None):
+ self.verify()
+
+ progress(0)
+
command = "x" if self.fullpath else "e"
- p = self.call_unrar(command, self.file, self.out, password=password)
+ p = self.call_cmd(command, self.file, self.out, password=self.password)
+
renice(p.pid, self.renice)
- progress(0)
progressstring = ""
while True:
c = p.stdout.read(1)
@@ -137,7 +165,7 @@ class UnRar(AbtractExtractor):
if not c:
break
# reading a percentage sign -> set progress and restart
- if c == '%':
+ if c is '%':
progress(int(progressstring))
progressstring = ""
# not reading a digit -> therefore restart
@@ -145,42 +173,43 @@ class UnRar(AbtractExtractor):
progressstring = ""
# add digit to progressstring
else:
- progressstring = progressstring + c
+ progressstring += c
+
progress(100)
+ self.files = self.list()
+
# retrieve stderr
- err = p.stderr.read()
-
- if "CRC failed" in err and not password and not self.passwordProtected:
- raise CRCError
- elif "CRC failed" in err:
- raise WrongPassword
- if err.strip(): #: raise error if anything is on stderr
- raise ArchiveError(err.strip())
+ self.check(err=p.stderr.read())
+
if p.returncode:
raise ArchiveError("Process terminated")
- if not self.files:
- self.password = password
- self.listContent()
def getDeleteFiles(self):
- if ".part" in self.file:
- return glob(re.sub("(?<=\.part)([01]+)", "*", self.file, re.IGNORECASE))
+ if ".part" in basename(self.file):
+ return glob(re.sub("(?<=\.part)([01]+)", "*", self.file, re.I))
+
# get files which matches .r* and filter unsuited files out
- parts = glob(re.sub(r"(?<=\.r)ar$", "*", self.file, re.IGNORECASE))
- return filter(lambda x: self.re_partfiles.match(x), parts)
+ parts = glob(re.sub(r"(?<=\.r)ar$", "*", self.file, re.I))
+
+ return filter(lambda x: self.re_rarfile.match(x), parts)
+
- def listContent(self):
+ def list(self):
command = "vb" if self.fullpath else "lb"
- p = self.call_unrar(command, "-v", self.file, password=self.password)
+
+ p = self.call_cmd(command, "-v", self.file, password=self.password)
out, err = p.communicate()
- if "Cannot open" in err:
- raise ArchiveError("Cannot open file")
+ if err.strip():
+ self.m.logError(err)
+ if "Cannot open" in err:
+ return list()
- if err.strip(): #: only log error at this point
- self.m.logError(err.strip())
+ if p.returncode:
+ self.m.logError("Process terminated")
+ return list()
result = set()
@@ -188,16 +217,22 @@ class UnRar(AbtractExtractor):
f = f.strip()
result.add(save_join(self.out, f))
- self.files = result
+ return list(result)
- def call_unrar(self, command, *xargs, **kwargs):
+
+ def call_cmd(self, command, *xargs, **kwargs):
args = []
+
# overwrite flag
- args.append("-o+") if self.overwrite else args.append("-o-")
+ if self.overwrite:
+ args.append("-o+")
+ else:
+ args.append("-o-")
+ if self.delete:
+ args.append("-or")
- if self.excludefiles:
- for word in self.excludefiles.split(';'):
- args.append("-x%s" % word)
+ for word in self.excludefiles:
+ args.append("-x%s" % word.strip())
# assume yes on all queries
args.append("-y")
@@ -208,18 +243,11 @@ class UnRar(AbtractExtractor):
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.m.logDebug(" ".join(call))
- p = Popen(call, stdout=PIPE, stderr=PIPE)
-
- return p
-
-
-def renice(pid, value):
- if os.name != "nt" and value:
- try:
- Popen(["renice", str(value), str(pid)], stdout=PIPE, stderr=PIPE, bufsize=-1)
- except:
- print "Renice failed"
+ return Popen(call, stdout=PIPE, stderr=PIPE)
diff --git a/module/plugins/internal/UnZip.py b/module/plugins/internal/UnZip.py
index bace76789..5ec56cbdf 100644
--- a/module/plugins/internal/UnZip.py
+++ b/module/plugins/internal/UnZip.py
@@ -1,53 +1,86 @@
# -*- coding: utf-8 -*-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
+from __future__ import with_statement
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-import zipfile
import sys
+import zipfile
-from module.plugins.internal.AbstractExtractor import AbtractExtractor
+from module.plugins.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError
-class UnZip(AbtractExtractor):
- __name__ = "UnZip"
- __version__ = "0.1"
+class UnZip(Extractor):
+ __name__ = "UnZip"
+ __version__ = "1.01"
__description__ = """Zip extractor plugin"""
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+ EXTENSIONS = ["zip", "zip64"]
- @staticmethod
- def checkDeps():
+
+ @classmethod
+ def checkDeps(cls):
return sys.version_info[:2] >= (2, 6)
- @staticmethod
- def getTargets(files_ids):
- result = []
- for file, id in files_ids:
- if file.endswith(".zip"):
- result.append((file, id))
+ @classmethod
+ def isArchive(cls, file):
+ return zipfile.is_zipfile(file)
+
+
+ def verify(self):
+ try:
+ with zipfile.ZipFile(self.file, 'r', allowZip64=True) as z:
+ z.setpassword(self.password)
+ badcrc = z.testzip()
+
+ except (BadZipfile, LargeZipFile), e:
+ raise ArchiveError(e)
+
+ except RuntimeError, e:
+ if 'encrypted' in e:
+ raise PasswordError
+ else:
+ raise ArchiveError(e)
+
+ else:
+ if badcrc:
+ raise CRCError
+
+ if not self.list():
+ raise ArchiveError("Empty archive")
+
+
+ def list(self):
+ try:
+ with zipfile.ZipFile(self.file, 'r', allowZip64=True) as z:
+ z.setpassword(self.password)
+ return z.namelist()
+ except Exception:
+ return list()
+
+
+ def extract(self, progress=lambda x: None):
+ try:
+ with zipfile.ZipFile(self.file, 'r', allowZip64=True) as z:
+ progress(0)
+ z.extractall(self.out, pwd=self.password)
+ progress(100)
+
+ except (BadZipfile, LargeZipFile), e:
+ raise ArchiveError(e)
+
+ except RuntimeError, e:
+ if e is "Bad password for file":
+ raise PasswordError
+ else:
+ raise ArchiveError(e)
- return result
+ finally:
+ self.files = self.list()
- def extract(self, progress, password=None):
- z = zipfile.ZipFile(self.file)
- self.files = z.namelist()
- z.extractall(self.out)
def getDeleteFiles(self):
return [self.file]
diff --git a/module/plugins/internal/XFSAccount.py b/module/plugins/internal/XFSAccount.py
new file mode 100644
index 000000000..2784ecd0b
--- /dev/null
+++ b/module/plugins/internal/XFSAccount.py
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from time import gmtime, mktime, strptime
+from urlparse import urljoin
+
+from module.plugins.Account import Account
+from module.plugins.internal.SimpleHoster import parseHtmlForm, set_cookies
+
+
+class XFSAccount(Account):
+ __name__ = "XFSAccount"
+ __type__ = "account"
+ __version__ = "0.33"
+
+ __description__ = """XFileSharing account plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = None
+ HOSTER_URL = None
+
+ COOKIES = [(HOSTER_DOMAIN, "lang", "english")]
+
+ PREMIUM_PATTERN = r'\(Premium only\)'
+
+ VALID_UNTIL_PATTERN = r'Premium.[Aa]ccount expire:.*?(\d{1,2} [\w^_]+ \d{4})'
+
+ TRAFFIC_LEFT_PATTERN = r'Traffic available today:.*?<b>\s*(?P<S>[\d.,]+|[Uu]nlimited)\s*(?:(?P<U>[\w^_]+)\s*)?</b>'
+ TRAFFIC_LEFT_UNIT = "MB" #: used only if no group <U> was found
+
+ LEECH_TRAFFIC_PATTERN = r'Leech Traffic left:<b>.*?(?P<S>[\d.,]+|[Uu]nlimited)\s*(?:(?P<U>[\w^_]+)\s*)?</b>'
+ LEECH_TRAFFIC_UNIT = "MB" #: used only if no group <U> was found
+
+ LOGIN_FAIL_PATTERN = r'>\s*(Incorrect Login or Password|Error<)'
+
+
+ def __init__(self, manager, accounts): #@TODO: remove in 0.4.10
+ self.init()
+ return super(XFSAccount, self).__init__(manager, accounts)
+
+
+ def init(self):
+ if not self.HOSTER_DOMAIN:
+ self.logError(_("Missing HOSTER_DOMAIN"))
+
+ if not self.HOSTER_URL:
+ self.HOSTER_URL = "http://www.%s/" % self.HOSTER_DOMAIN or ""
+
+
+ def loadAccountInfo(self, user, req):
+ validuntil = None
+ trafficleft = None
+ leechtraffic = None
+ premium = None
+
+ html = req.load(self.HOSTER_URL, get={'op': "my_account"}, decode=True)
+
+ premium = True if re.search(self.PREMIUM_PATTERN, html) else False
+
+ m = re.search(self.VALID_UNTIL_PATTERN, html)
+ if m:
+ expiredate = m.group(1).strip()
+ self.logDebug("Expire date: " + expiredate)
+
+ try:
+ validuntil = mktime(strptime(expiredate, "%d %B %Y"))
+
+ except Exception, e:
+ self.logError(e)
+
+ else:
+ self.logDebug("Valid until: %s" % validuntil)
+
+ if validuntil > mktime(gmtime()):
+ premium = True
+ trafficleft = -1
+ else:
+ premium = False
+ validuntil = None #: registered account type (not premium)
+ else:
+ self.logDebug("VALID_UNTIL_PATTERN not found")
+
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+ if m:
+ try:
+ traffic = m.groupdict()
+ size = traffic['S']
+
+ if "nlimited" in size:
+ trafficleft = -1
+ if validuntil is None:
+ validuntil = -1
+ else:
+ if 'U' in traffic:
+ unit = traffic['U']
+ elif isinstance(self.TRAFFIC_LEFT_UNIT, basestring):
+ unit = self.TRAFFIC_LEFT_UNIT
+ else:
+ unit = ""
+
+ trafficleft = self.parseTraffic(size + unit)
+
+ except Exception, e:
+ self.logError(e)
+ else:
+ self.logDebug("TRAFFIC_LEFT_PATTERN not found")
+
+ leech = [m.groupdict() for m in re.finditer(self.LEECH_TRAFFIC_PATTERN, html)]
+ if leech:
+ leechtraffic = 0
+ try:
+ for traffic in leech:
+ size = traffic['S']
+
+ if "nlimited" in size:
+ leechtraffic = -1
+ if validuntil is None:
+ validuntil = -1
+ break
+ else:
+ if 'U' in traffic:
+ unit = traffic['U']
+ elif isinstance(self.LEECH_TRAFFIC_UNIT, basestring):
+ unit = self.LEECH_TRAFFIC_UNIT
+ else:
+ unit = ""
+
+ leechtraffic += self.parseTraffic(size + unit)
+
+ except Exception, e:
+ self.logError(e)
+ else:
+ self.logDebug("LEECH_TRAFFIC_PATTERN not found")
+
+ return {'validuntil': validuntil, 'trafficleft': trafficleft, 'leechtraffic': leechtraffic, 'premium': premium}
+
+
+ def login(self, user, data, req):
+ if isinstance(self.COOKIES, list):
+ set_cookies(req.cj, self.COOKIES)
+
+ url = urljoin(self.HOSTER_URL, "login.html")
+ html = req.load(url, decode=True)
+
+ action, inputs = parseHtmlForm('name="FL"', html)
+ if not inputs:
+ inputs = {'op': "login",
+ 'redirect': self.HOSTER_URL}
+
+ inputs.update({'login': user,
+ 'password': data['password']})
+
+ html = req.load(self.HOSTER_URL, post=inputs, decode=True)
+
+ if re.search(self.LOGIN_FAIL_PATTERN, html):
+ self.wrongPassword()
diff --git a/module/plugins/internal/XFSCrypter.py b/module/plugins/internal/XFSCrypter.py
new file mode 100644
index 000000000..4b57dab90
--- /dev/null
+++ b/module/plugins/internal/XFSCrypter.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
+
+
+class XFSCrypter(SimpleCrypter):
+ __name__ = "XFSCrypter"
+ __type__ = "crypter"
+ __version__ = "0.05"
+
+ __pattern__ = r'^unmatchable$'
+
+ __description__ = """XFileSharing decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ HOSTER_DOMAIN = None
+ HOSTER_NAME = None
+
+ URL_REPLACEMENTS = [(r'&?per_page=\d+', ""), (r'[?/&]+$', ""), (r'(.+/[^?]+)$', r'\1?'), (r'$', r'&per_page=10000')]
+
+ COOKIES = [(HOSTER_DOMAIN, "lang", "english")]
+
+ 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)'
diff --git a/module/plugins/internal/XFSHoster.py b/module/plugins/internal/XFSHoster.py
new file mode 100644
index 000000000..f2168d0c7
--- /dev/null
+++ b/module/plugins/internal/XFSHoster.py
@@ -0,0 +1,341 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from random import random
+from time import sleep
+
+from pycurl import FOLLOWLOCATION, LOW_SPEED_TIME
+
+from module.plugins.internal.CaptchaService import ReCaptcha, SolveMedia
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, secondsToMidnight
+from module.utils import html_unescape
+
+
+class XFSHoster(SimpleHoster):
+ __name__ = "XFSHoster"
+ __type__ = "hoster"
+ __version__ = "0.33"
+
+ __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
+ HOSTER_NAME = None
+
+ TEXT_ENCODING = False
+ COOKIES = [(HOSTER_DOMAIN, "lang", "english")]
+ 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
+ self.resumeDownload = self.multiDL = self.premium
+
+
+ def prepare(self):
+ """ Initialize important variables """
+ if not self.HOSTER_DOMAIN:
+ self.fail(_("Missing HOSTER_DOMAIN"))
+
+ if not self.HOSTER_NAME:
+ self.HOSTER_NAME = "".join([str.capitalize() for str in self.HOSTER_DOMAIN.split('.')])
+
+ 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
+ self.passwords = self.getPassword().splitlines()
+
+ super(XFSHoster, self).prepare()
+
+ if self.DIRECT_LINK is None:
+ self.directDL = bool(self.premium)
+
+
+ def handleFree(self):
+ link = self.getDownloadLink()
+
+ if link:
+ if self.captcha:
+ self.correctCaptcha()
+
+ self.download(link, ref=True, cookies=True, disposition=True)
+
+ elif self.errmsg:
+ if 'captcha' in self.errmsg:
+ self.fail(_("No valid captcha code entered"))
+ else:
+ self.fail(self.errmsg)
+
+ else:
+ self.fail(_("Download link not found"))
+
+
+ def handlePremium(self):
+ return self.handleFree()
+
+
+ def getDownloadLink(self):
+ 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.req.http.c.setopt(FOLLOWLOCATION, 0)
+
+ self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True)
+
+ self.req.http.c.setopt(FOLLOWLOCATION, 1)
+
+ 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.errmsg = None
+
+ return m.group(1).strip() #@TODO: Remove .strip() in 0.4.10
+
+
+ def handleMulti(self):
+ 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'] = self.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']
+ else:
+ self.fail(_("Download link not found"))
+
+
+ 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:
+ if self.passwords:
+ inputs['password'] = self.passwords.pop(0)
+ 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:
+ captcha_key = recaptcha.detect_key()
+ else:
+ self.logDebug("ReCaptcha key: %s" % captcha_key)
+
+ if captcha_key:
+ inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(captcha_key)
+ return 3
+
+ solvemedia = SolveMedia(self)
+ try:
+ captcha_key = re.search(self.SOLVEMEDIA_PATTERN, self.html).group(1)
+ except:
+ captcha_key = solvemedia.detect_key()
+ else:
+ self.logDebug("SolveMedia key: %s" % captcha_key)
+
+ if captcha_key:
+ inputs['adcopy_challenge'], inputs['adcopy_response'] = solvemedia.challenge(captcha_key)
+ return 4
+
+ return 0
diff --git a/module/plugins/internal/XFSPAccount.py b/module/plugins/internal/XFSPAccount.py
deleted file mode 100644
index a1cba9af3..000000000
--- a/module/plugins/internal/XFSPAccount.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-"""
-
-import re
-from time import mktime, strptime
-from module.plugins.Account import Account
-from module.plugins.internal.SimpleHoster import parseHtmlForm
-from module.utils import parseFileSize
-
-
-class XFSPAccount(Account):
- __name__ = "XFSPAccount"
- __version__ = "0.06"
- __type__ = "account"
-
- __description__ = """XFileSharingPro base account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
- MAIN_PAGE = None
-
- VALID_UNTIL_PATTERN = r'>Premium.[Aa]ccount expire:</TD><TD><b>([^<]+)</b>'
- TRAFFIC_LEFT_PATTERN = r'>Traffic available today:</TD><TD><b>([^<]+)</b>'
- LOGIN_FAIL_PATTERN = r'Incorrect Login or Password|>Error<'
- PREMIUM_PATTERN = r'>Renew premium<'
-
-
- def loadAccountInfo(self, user, req):
- html = req.load(self.MAIN_PAGE + "?op=my_account", decode=True)
-
- validuntil = trafficleft = None
- premium = True if re.search(self.PREMIUM_PATTERN, html) else False
-
- m = re.search(self.VALID_UNTIL_PATTERN, html)
- if m:
- premium = True
- trafficleft = -1
- try:
- self.logDebug(m.group(1))
- validuntil = mktime(strptime(m.group(1), "%d %B %Y"))
- except Exception, e:
- self.logError(e)
- else:
- m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- if m:
- trafficleft = m.group(1)
- if "Unlimited" in trafficleft:
- premium = True
- else:
- trafficleft = parseFileSize(trafficleft) / 1024
-
- return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}
-
- def login(self, user, data, req):
- html = req.load('%slogin.html' % self.MAIN_PAGE, decode=True)
-
- action, inputs = parseHtmlForm('name="FL"', html)
- if not inputs:
- inputs = {"op": "login",
- "redirect": self.MAIN_PAGE}
-
- inputs.update({"login": user,
- "password": data['password']})
-
- html = req.load(self.MAIN_PAGE, post=inputs, decode=True)
-
- if re.search(self.LOGIN_FAIL_PATTERN, html):
- self.wrongPassword()