summaryrefslogtreecommitdiffstats
path: root/module/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'module/plugins')
-rw-r--r--module/plugins/Account.py10
-rw-r--r--module/plugins/AccountManager.py47
-rw-r--r--module/plugins/Container.py22
-rw-r--r--module/plugins/Crypter.py27
-rw-r--r--module/plugins/Hook.py26
-rw-r--r--module/plugins/Hoster.py6
-rw-r--r--module/plugins/Plugin.py8
-rw-r--r--module/plugins/PluginManager.py9
-rw-r--r--module/plugins/ReCaptcha.py22
-rw-r--r--module/plugins/accounts/AlldebridCom.py43
-rw-r--r--module/plugins/accounts/BayfilesCom.py51
-rw-r--r--module/plugins/accounts/BillionuploadsCom.py16
-rw-r--r--module/plugins/accounts/BitshareCom.py39
-rw-r--r--module/plugins/accounts/CatShareNet.py56
-rw-r--r--module/plugins/accounts/CloudzillaTo.py36
-rw-r--r--module/plugins/accounts/CramitIn.py18
-rw-r--r--module/plugins/accounts/CyberlockerCh.py33
-rw-r--r--module/plugins/accounts/CzshareCom.py47
-rw-r--r--module/plugins/accounts/DdlstorageCom.py52
-rw-r--r--module/plugins/accounts/DebridItaliaCom.py60
-rw-r--r--module/plugins/accounts/DepositfilesCom.py46
-rw-r--r--module/plugins/accounts/EasybytezCom.py77
-rw-r--r--module/plugins/accounts/EgoFilesCom.py42
-rw-r--r--module/plugins/accounts/EuroshareEu.py37
-rw-r--r--module/plugins/accounts/FastixRu.py30
-rw-r--r--module/plugins/accounts/FastshareCz.py66
-rw-r--r--module/plugins/accounts/File4safeCom.py19
-rw-r--r--module/plugins/accounts/FileParadoxIn.py16
-rw-r--r--module/plugins/accounts/FilecloudIo.py41
-rw-r--r--module/plugins/accounts/FilefactoryCom.py33
-rw-r--r--module/plugins/accounts/FilejungleCom.py39
-rw-r--r--module/plugins/accounts/FileomCom.py16
-rw-r--r--module/plugins/accounts/FilerNet.py57
-rw-r--r--module/plugins/accounts/FilerioCom.py18
-rw-r--r--module/plugins/accounts/FilesMailRu.py34
-rw-r--r--module/plugins/accounts/FileserveCom.py50
-rw-r--r--module/plugins/accounts/FourSharedCom.py58
-rw-r--r--module/plugins/accounts/FreakshareCom.py64
-rw-r--r--module/plugins/accounts/FreeWayMe.py50
-rw-r--r--module/plugins/accounts/FshareVn.py55
-rw-r--r--module/plugins/accounts/Ftp.py13
-rw-r--r--module/plugins/accounts/HellshareCz.py51
-rw-r--r--module/plugins/accounts/HotfileCom.py89
-rw-r--r--module/plugins/accounts/Http.py13
-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.py31
-rw-r--r--module/plugins/accounts/LinestorageCom.py17
-rw-r--r--module/plugins/accounts/LinksnappyCom.py15
-rw-r--r--module/plugins/accounts/MegaDebridEu.py44
-rw-r--r--module/plugins/accounts/MegaRapidCz.py59
-rw-r--r--module/plugins/accounts/MegasharesCom.py12
-rw-r--r--module/plugins/accounts/MovReelCom.py23
-rw-r--r--module/plugins/accounts/MultiDebridCom.py46
-rw-r--r--module/plugins/accounts/MultishareCz.py41
-rw-r--r--module/plugins/accounts/MyfastfileCom.py35
-rwxr-xr-xmodule/plugins/accounts/NetloadIn.py39
-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.py68
-rw-r--r--module/plugins/accounts/OneFichierCom.py53
-rw-r--r--module/plugins/accounts/OverLoadMe.py23
-rw-r--r--module/plugins/accounts/Premium4Me.py27
-rw-r--r--module/plugins/accounts/PremiumTo.py34
-rw-r--r--module/plugins/accounts/PremiumizeMe.py23
-rw-r--r--module/plugins/accounts/QuickshareCz.py41
-rw-r--r--module/plugins/accounts/RPNetBiz.py32
-rw-r--r--module/plugins/accounts/RapideoPl.py80
-rw-r--r--module/plugins/accounts/RapidfileshareNet.py18
-rw-r--r--module/plugins/accounts/RapidgatorNet.py33
-rw-r--r--module/plugins/accounts/RapidshareCom.py69
-rw-r--r--module/plugins/accounts/RapiduNet.py47
-rw-r--r--module/plugins/accounts/RarefileNet.py18
-rw-r--r--module/plugins/accounts/RealdebridCom.py27
-rw-r--r--module/plugins/accounts/RehostTo.py40
-rw-r--r--module/plugins/accounts/ReloadCc.py75
-rw-r--r--module/plugins/accounts/RyushareCom.py22
-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/ShareRapidCom.py49
-rw-r--r--module/plugins/accounts/ShareonlineBiz.py85
-rw-r--r--module/plugins/accounts/SimplyPremiumCom.py54
-rw-r--r--module/plugins/accounts/SimplydebridCom.py23
-rw-r--r--module/plugins/accounts/StahnuTo.py39
-rw-r--r--module/plugins/accounts/StreamcloudEu.py16
-rw-r--r--module/plugins/accounts/TurbobitNet.py36
-rw-r--r--module/plugins/accounts/TusfilesNet.py23
-rw-r--r--module/plugins/accounts/UlozTo.py51
-rw-r--r--module/plugins/accounts/UnrestrictLi.py37
-rw-r--r--module/plugins/accounts/UploadcCom.py16
-rw-r--r--module/plugins/accounts/UploadedTo.py84
-rw-r--r--module/plugins/accounts/UploadheroCom.py27
-rw-r--r--module/plugins/accounts/UploadingCom.py80
-rw-r--r--module/plugins/accounts/UptoboxCom.py19
-rw-r--r--module/plugins/accounts/VidPlayNet.py16
-rw-r--r--module/plugins/accounts/Vipleech4uCom.py41
-rw-r--r--module/plugins/accounts/WarserverCz.py68
-rw-r--r--module/plugins/accounts/WebshareCz.py68
-rw-r--r--module/plugins/accounts/XFileSharingPro.py34
-rw-r--r--module/plugins/accounts/YibaishiwuCom.py35
-rw-r--r--module/plugins/accounts/ZeveraCom.py30
-rw-r--r--module/plugins/captcha/GigasizeCom.py20
-rw-r--r--module/plugins/captcha/LinksaveIn.py39
-rw-r--r--module/plugins/captcha/NetloadIn.py21
-rw-r--r--module/plugins/captcha/ShareonlineBiz.py38
-rw-r--r--module/plugins/captcha/captcha.py163
-rw-r--r--module/plugins/container/CCF.py35
-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.py24
-rw-r--r--module/plugins/container/RSDF.py35
-rw-r--r--module/plugins/crypter/BitshareComFolder.py40
-rw-r--r--module/plugins/crypter/C1neonCom.py18
-rw-r--r--module/plugins/crypter/ChipDe.py27
-rw-r--r--module/plugins/crypter/CloudzillaToFolder.py43
-rw-r--r--module/plugins/crypter/CrockoComFolder.py20
-rw-r--r--module/plugins/crypter/CryptItCom.py18
-rw-r--r--module/plugins/crypter/CzshareComFolder.py31
-rw-r--r--module/plugins/crypter/DDLMusicOrg.py25
-rw-r--r--module/plugins/crypter/DailymotionBatch.py61
-rw-r--r--module/plugins/crypter/DataHuFolder.py65
-rw-r--r--module/plugins/crypter/DdlstorageComFolder.py37
-rw-r--r--module/plugins/crypter/DepositfilesComFolder.py20
-rw-r--r--module/plugins/crypter/Dereferer.py38
-rw-r--r--module/plugins/crypter/DevhostStFolder.py61
-rw-r--r--module/plugins/crypter/DlProtectCom.py48
-rw-r--r--module/plugins/crypter/DontKnowMe.py27
-rw-r--r--module/plugins/crypter/DownloadVimeoCom.py30
-rw-r--r--module/plugins/crypter/DuckCryptInfo.py64
-rw-r--r--module/plugins/crypter/DuploadOrgFolder.py36
-rw-r--r--module/plugins/crypter/EasybytezComFolder.py55
-rw-r--r--module/plugins/crypter/EmbeduploadCom.py53
-rw-r--r--module/plugins/crypter/FilebeerInfoFolder.py18
-rw-r--r--module/plugins/crypter/FilecloudIoFolder.py24
-rw-r--r--module/plugins/crypter/FilecryptCc.py170
-rw-r--r--module/plugins/crypter/FilefactoryComFolder.py66
-rw-r--r--module/plugins/crypter/FilerNetFolder.py29
-rw-r--r--module/plugins/crypter/FileserveComFolder.py25
-rw-r--r--module/plugins/crypter/FilesonicComFolder.py18
-rw-r--r--module/plugins/crypter/FilestubeCom.py40
-rw-r--r--module/plugins/crypter/FiletramCom.py43
-rw-r--r--module/plugins/crypter/FiredriveComFolder.py19
-rw-r--r--module/plugins/crypter/FourChanOrg.py26
-rw-r--r--module/plugins/crypter/FreakhareComFolder.py41
-rw-r--r--module/plugins/crypter/FreetexthostCom.py40
-rw-r--r--module/plugins/crypter/FshareVnFolder.py20
-rw-r--r--module/plugins/crypter/Go4UpCom.py49
-rw-r--r--module/plugins/crypter/GooGl.py38
-rw-r--r--module/plugins/crypter/HoerbuchIn.py41
-rw-r--r--module/plugins/crypter/HotfileComFolder.py19
-rw-r--r--module/plugins/crypter/HotfileFolderCom.py27
-rw-r--r--module/plugins/crypter/ILoadTo.py18
-rw-r--r--module/plugins/crypter/ImgurComAlbum.py30
-rw-r--r--module/plugins/crypter/JunocloudMeFolder.py23
-rw-r--r--module/plugins/crypter/LetitbitNetFolder.py32
-rw-r--r--module/plugins/crypter/LinkCryptWs.py327
-rw-r--r--module/plugins/crypter/LinkSaveIn.py230
-rw-r--r--module/plugins/crypter/LinkdecrypterCom.py72
-rw-r--r--module/plugins/crypter/LixIn.py72
-rw-r--r--module/plugins/crypter/LofCc.py18
-rw-r--r--module/plugins/crypter/MBLinkInfo.py19
-rw-r--r--module/plugins/crypter/MediafireComFolder.py53
-rw-r--r--module/plugins/crypter/MegaRapidCzFolder.py23
-rw-r--r--module/plugins/crypter/MegauploadComFolder.py18
-rw-r--r--module/plugins/crypter/Movie2kTo.py18
-rw-r--r--module/plugins/crypter/MultiUpOrg.py44
-rw-r--r--module/plugins/crypter/MultiloadCz.py44
-rw-r--r--module/plugins/crypter/MultiuploadCom.py67
-rw-r--r--module/plugins/crypter/NCryptIn.py109
-rw-r--r--module/plugins/crypter/NetfolderIn.py54
-rw-r--r--module/plugins/crypter/NosvideoCom.py24
-rw-r--r--module/plugins/crypter/OneKhDe.py28
-rwxr-xr-xmodule/plugins/crypter/OronComFolder.py18
-rw-r--r--module/plugins/crypter/PastebinCom.py38
-rw-r--r--module/plugins/crypter/QuickshareCzFolder.py34
-rw-r--r--module/plugins/crypter/RSLayerCom.py18
-rw-r--r--module/plugins/crypter/RapidfileshareNetFolder.py23
-rw-r--r--module/plugins/crypter/RelinkUs.py141
-rw-r--r--module/plugins/crypter/SafelinkingNet.py63
-rw-r--r--module/plugins/crypter/SecuredIn.py18
-rw-r--r--module/plugins/crypter/SerienjunkiesOrg.py318
-rw-r--r--module/plugins/crypter/SexuriaCom.py94
-rw-r--r--module/plugins/crypter/ShareLinksBiz.py87
-rw-r--r--module/plugins/crypter/ShareRapidComFolder.py15
-rw-r--r--module/plugins/crypter/SharingmatrixComFolder.py18
-rw-r--r--module/plugins/crypter/SpeedLoadOrgFolder.py32
-rw-r--r--module/plugins/crypter/StealthTo.py51
-rw-r--r--module/plugins/crypter/TnyCz.py40
-rw-r--r--module/plugins/crypter/TrailerzoneInfo.py18
-rw-r--r--module/plugins/crypter/TurbobitNetFolder.py47
-rw-r--r--module/plugins/crypter/TusfilesNetFolder.py53
-rw-r--r--module/plugins/crypter/UlozToFolder.py42
-rw-r--r--module/plugins/crypter/UploadableChFolder.py27
-rw-r--r--module/plugins/crypter/UploadedToFolder.py56
-rw-r--r--module/plugins/crypter/WiiReloadedOrg.py18
-rw-r--r--module/plugins/crypter/WuploadComFolder.py18
-rw-r--r--module/plugins/crypter/XFileSharingProFolder.py50
-rw-r--r--module/plugins/crypter/XupPl.py21
-rw-r--r--module/plugins/crypter/YoutubeBatch.py111
-rw-r--r--module/plugins/hooks/AlldebridCom.py22
-rw-r--r--module/plugins/hooks/BypassCaptcha.py98
-rwxr-xr-xmodule/plugins/hooks/Captcha9kw.py343
-rw-r--r--module/plugins/hooks/CaptchaBrotherhood.py108
-rw-r--r--module/plugins/hooks/CaptchaTrader.py157
-rw-r--r--module/plugins/hooks/Checksum.py113
-rw-r--r--module/plugins/hooks/ClickAndLoad.py69
-rw-r--r--module/plugins/hooks/DeathByCaptcha.py128
-rw-r--r--module/plugins/hooks/DebridItaliaCom.py51
-rw-r--r--module/plugins/hooks/DeleteFinished.py57
-rw-r--r--module/plugins/hooks/DownloadScheduler.py51
-rw-r--r--module/plugins/hooks/EasybytezCom.py37
-rw-r--r--module/plugins/hooks/Ev0InFetcher.py90
-rw-r--r--module/plugins/hooks/ExpertDecoders.py78
-rw-r--r--module/plugins/hooks/ExternalScripts.py111
-rw-r--r--module/plugins/hooks/ExtractArchive.py350
-rw-r--r--module/plugins/hooks/FastixRu.py29
-rw-r--r--module/plugins/hooks/FreeWayMe.py43
-rw-r--r--module/plugins/hooks/HotFolder.py97
-rw-r--r--module/plugins/hooks/IRCInterface.py158
-rw-r--r--module/plugins/hooks/ImageTyperz.py114
-rw-r--r--module/plugins/hooks/LinkdecrypterCom.py59
-rw-r--r--module/plugins/hooks/LinksnappyCom.py23
-rw-r--r--module/plugins/hooks/MegaDebridEu.py44
-rw-r--r--module/plugins/hooks/MergeFiles.py125
-rw-r--r--module/plugins/hooks/MultiDebridCom.py41
-rw-r--r--module/plugins/hooks/MultiHome.py50
-rw-r--r--module/plugins/hooks/MultishareCz.py21
-rw-r--r--module/plugins/hooks/MyfastfileCom.py28
-rw-r--r--module/plugins/hooks/OverLoadMe.py25
-rw-r--r--module/plugins/hooks/Premium4Me.py32
-rw-r--r--module/plugins/hooks/PremiumTo.py37
-rw-r--r--module/plugins/hooks/PremiumizeMe.py34
-rw-r--r--module/plugins/hooks/RPNetBiz.py35
-rw-r--r--module/plugins/hooks/RapideoPl.py31
-rw-r--r--module/plugins/hooks/RealdebridCom.py19
-rw-r--r--module/plugins/hooks/RehostTo.py30
-rw-r--r--module/plugins/hooks/ReloadCc.py67
-rw-r--r--module/plugins/hooks/RestartFailed.py67
-rw-r--r--module/plugins/hooks/RestartSlow.py61
-rw-r--r--module/plugins/hooks/SimplyPremiumCom.py40
-rw-r--r--module/plugins/hooks/SimplydebridCom.py22
-rw-r--r--module/plugins/hooks/SkipRev.py108
-rw-r--r--module/plugins/hooks/UnSkipOnFail.py154
-rw-r--r--module/plugins/hooks/UnrestrictLi.py39
-rw-r--r--module/plugins/hooks/UpdateManager.py395
-rw-r--r--module/plugins/hooks/Vipleech4uCom.py80
-rw-r--r--module/plugins/hooks/WindowsPhoneToastNotify.py46
-rw-r--r--module/plugins/hooks/XFileSharingPro.py176
-rw-r--r--module/plugins/hooks/XMPPInterface.py81
-rw-r--r--module/plugins/hooks/ZeveraCom.py22
-rw-r--r--module/plugins/hoster/AlldebridCom.py99
-rw-r--r--module/plugins/hoster/BasePlugin.py139
-rw-r--r--module/plugins/hoster/BayfilesCom.py95
-rw-r--r--module/plugins/hoster/BezvadataCz.py84
-rw-r--r--module/plugins/hoster/BillionuploadsCom.py25
-rw-r--r--module/plugins/hoster/BitshareCom.py132
-rw-r--r--module/plugins/hoster/BoltsharingCom.py12
-rw-r--r--module/plugins/hoster/CatShareNet.py71
-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.py62
-rw-r--r--module/plugins/hoster/CyberlockerCh.py12
-rw-r--r--module/plugins/hoster/CzshareCom.py126
-rw-r--r--module/plugins/hoster/DailymotionCom.py88
-rw-r--r--module/plugins/hoster/DataHu.py58
-rw-r--r--module/plugins/hoster/DataportCz.py56
-rw-r--r--module/plugins/hoster/DateiTo.py96
-rw-r--r--module/plugins/hoster/DdlstorageCom.py90
-rw-r--r--module/plugins/hoster/DebridItaliaCom.py76
-rw-r--r--module/plugins/hoster/DepositfilesCom.py100
-rw-r--r--module/plugins/hoster/DevhostSt.py48
-rw-r--r--module/plugins/hoster/DlFreeFr.py145
-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.py44
-rw-r--r--module/plugins/hoster/EdiskCz.py57
-rw-r--r--module/plugins/hoster/EgoFilesCom.py98
-rw-r--r--module/plugins/hoster/EnteruploadCom.py18
-rw-r--r--module/plugins/hoster/EpicShareNet.py22
-rw-r--r--module/plugins/hoster/EuroshareEu.py54
-rw-r--r--module/plugins/hoster/ExtabitCom.py80
-rw-r--r--module/plugins/hoster/FastixRu.py83
-rw-r--r--module/plugins/hoster/FastshareCz.py116
-rw-r--r--module/plugins/hoster/File4safeCom.py36
-rw-r--r--module/plugins/hoster/FileApeCom.py12
-rw-r--r--module/plugins/hoster/FileParadoxIn.py23
-rw-r--r--module/plugins/hoster/FileSharkPl.py140
-rw-r--r--module/plugins/hoster/FileStoreTo.py41
-rw-r--r--module/plugins/hoster/FilebeerInfo.py12
-rw-r--r--module/plugins/hoster/FilecloudIo.py147
-rw-r--r--module/plugins/hoster/FilefactoryCom.py132
-rw-r--r--module/plugins/hoster/FilejungleCom.py34
-rw-r--r--module/plugins/hoster/FileomCom.py49
-rw-r--r--module/plugins/hoster/FilepostCom.py145
-rw-r--r--module/plugins/hoster/FilepupNet.py51
-rw-r--r--module/plugins/hoster/FilerNet.py115
-rw-r--r--module/plugins/hoster/FilerioCom.py25
-rw-r--r--module/plugins/hoster/FilesMailRu.py38
-rw-r--r--module/plugins/hoster/FileserveCom.py162
-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.py18
-rw-r--r--module/plugins/hoster/FlyFilesNet.py28
-rw-r--r--module/plugins/hoster/FourSharedCom.py54
-rw-r--r--module/plugins/hoster/FreakshareCom.py64
-rw-r--r--module/plugins/hoster/FreeWayMe.py51
-rw-r--r--module/plugins/hoster/FreevideoCz.py68
-rw-r--r--module/plugins/hoster/FshareVn.py93
-rw-r--r--module/plugins/hoster/Ftp.py72
-rw-r--r--module/plugins/hoster/GamefrontCom.py56
-rw-r--r--module/plugins/hoster/GigapetaCom.py59
-rw-r--r--module/plugins/hoster/GooIm.py56
-rw-r--r--module/plugins/hoster/HellshareCz.py54
-rw-r--r--module/plugins/hoster/HellspyCz.py29
-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.py22
-rw-r--r--module/plugins/hoster/IcyFilesCom.py29
-rw-r--r--module/plugins/hoster/IfileIt.py84
-rw-r--r--module/plugins/hoster/IfolderRu.py60
-rw-r--r--module/plugins/hoster/JumbofilesCom.py28
-rw-r--r--module/plugins/hoster/JunocloudMe.py26
-rw-r--r--module/plugins/hoster/Keep2shareCC.py120
-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.py148
-rw-r--r--module/plugins/hoster/LinestorageCom.py21
-rw-r--r--module/plugins/hoster/LinksnappyCom.py83
-rw-r--r--module/plugins/hoster/LoadTo.py99
-rw-r--r--module/plugins/hoster/LomafileCom.py19
-rw-r--r--module/plugins/hoster/LuckyShareNet.py56
-rw-r--r--module/plugins/hoster/MediafireCom.py118
-rw-r--r--module/plugins/hoster/MegaCoNz.py171
-rw-r--r--module/plugins/hoster/MegaDebridEu.py84
-rw-r--r--module/plugins/hoster/MegaFilesSe.py21
-rw-r--r--module/plugins/hoster/MegaNz.py132
-rw-r--r--module/plugins/hoster/MegaRapidCz.py71
-rw-r--r--module/plugins/hoster/MegacrypterCom.py40
-rw-r--r--module/plugins/hoster/MegareleaseOrg.py36
-rw-r--r--module/plugins/hoster/MegasharesCom.py128
-rw-r--r--module/plugins/hoster/MegauploadCom.py18
-rw-r--r--module/plugins/hoster/MegavideoCom.py19
-rw-r--r--module/plugins/hoster/MovReelCom.py30
-rw-r--r--module/plugins/hoster/MultiDebridCom.py56
-rw-r--r--module/plugins/hoster/MultishareCz.py89
-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.py70
-rw-r--r--module/plugins/hoster/NetloadIn.py228
-rw-r--r--module/plugins/hoster/NosuploadCom.py31
-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.py102
-rw-r--r--module/plugins/hoster/OneFichierCom.py84
-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.py54
-rw-r--r--module/plugins/hoster/PornhubCom.py36
-rw-r--r--module/plugins/hoster/PotloadCom.py22
-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.py55
-rw-r--r--module/plugins/hoster/PrzeklejPl.py18
-rw-r--r--module/plugins/hoster/PutlockerCom.py53
-rw-r--r--module/plugins/hoster/QuickshareCz.py73
-rw-r--r--module/plugins/hoster/RPNetBiz.py116
-rw-r--r--module/plugins/hoster/RapideoPl.py102
-rw-r--r--module/plugins/hoster/RapidfileshareNet.py31
-rw-r--r--module/plugins/hoster/RapidgatorNet.py167
-rw-r--r--module/plugins/hoster/RapidshareCom.py228
-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.py27
-rw-r--r--module/plugins/hoster/RehostTo.py41
-rw-r--r--module/plugins/hoster/ReloadCc.py115
-rw-r--r--module/plugins/hoster/RemixshareCom.py61
-rw-r--r--module/plugins/hoster/RgHostNet.py31
-rw-r--r--module/plugins/hoster/RyushareCom.py63
-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.py73
-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/ShareRapidCom.py70
-rw-r--r--module/plugins/hoster/SharebeesCom.py12
-rw-r--r--module/plugins/hoster/ShareonlineBiz.py253
-rw-r--r--module/plugins/hoster/ShareplaceCom.py34
-rw-r--r--module/plugins/hoster/SharingmatrixCom.py19
-rw-r--r--module/plugins/hoster/ShragleCom.py13
-rw-r--r--module/plugins/hoster/SimplyPremiumCom.py152
-rw-r--r--module/plugins/hoster/SimplydebridCom.py78
-rw-r--r--module/plugins/hoster/SockshareCom.py96
-rw-r--r--module/plugins/hoster/SoundcloudCom.py41
-rw-r--r--module/plugins/hoster/SpeedLoadOrg.py12
-rw-r--r--module/plugins/hoster/SpeedfileCz.py29
-rw-r--r--module/plugins/hoster/SpeedyshareCom.py51
-rw-r--r--module/plugins/hoster/StorageTo.py18
-rw-r--r--module/plugins/hoster/StreamCz.py69
-rw-r--r--module/plugins/hoster/StreamcloudEu.py119
-rw-r--r--module/plugins/hoster/TurbobitNet.py144
-rw-r--r--module/plugins/hoster/TurbouploadCom.py29
-rw-r--r--module/plugins/hoster/TusfilesNet.py55
-rw-r--r--module/plugins/hoster/TwoSharedCom.py38
-rw-r--r--module/plugins/hoster/UlozTo.py133
-rw-r--r--module/plugins/hoster/UloziskoSk.py80
-rw-r--r--module/plugins/hoster/UnibytesCom.py70
-rw-r--r--module/plugins/hoster/UnrestrictLi.py132
-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.py126
-rw-r--r--module/plugins/hoster/UploadhereCom.py18
-rw-r--r--module/plugins/hoster/UploadheroCom.py89
-rw-r--r--module/plugins/hoster/UploadingCom.py102
-rw-r--r--module/plugins/hoster/UploadkingCom.py18
-rw-r--r--module/plugins/hoster/UpstoreNet.py55
-rw-r--r--module/plugins/hoster/UptoboxCom.py87
-rw-r--r--module/plugins/hoster/VeehdCom.py54
-rw-r--r--module/plugins/hoster/VeohCom.py67
-rw-r--r--module/plugins/hoster/VidPlayNet.py25
-rw-r--r--module/plugins/hoster/VimeoCom.py75
-rw-r--r--module/plugins/hoster/Vipleech4uCom.py86
-rw-r--r--module/plugins/hoster/WarserverCz.py75
-rw-r--r--module/plugins/hoster/WebshareCz.py99
-rw-r--r--module/plugins/hoster/WrzucTo.py47
-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.py84
-rw-r--r--module/plugins/hoster/XVideosCom.py19
-rw-r--r--module/plugins/hoster/Xdcc.py103
-rw-r--r--module/plugins/hoster/YibaishiwuCom.py71
-rw-r--r--module/plugins/hoster/YoupornCom.py29
-rw-r--r--module/plugins/hoster/YourfilesTo.py35
-rw-r--r--module/plugins/hoster/YoutubeCom.py86
-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.py85
-rw-r--r--module/plugins/internal/CaptchaService.py346
-rw-r--r--module/plugins/internal/DeadCrypter.py32
-rw-r--r--module/plugins/internal/DeadHoster.py36
-rw-r--r--module/plugins/internal/Extractor.py (renamed from module/plugins/internal/AbstractExtractor.py)93
-rw-r--r--module/plugins/internal/MultiHook.py218
-rw-r--r--module/plugins/internal/MultiHoster.py209
-rw-r--r--module/plugins/internal/SimpleCrypter.py176
-rw-r--r--module/plugins/internal/SimpleDereferer.py96
-rw-r--r--module/plugins/internal/SimpleHoster.py680
-rw-r--r--module/plugins/internal/UnRar.py277
-rw-r--r--module/plugins/internal/UnZip.py100
-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
475 files changed, 15323 insertions, 13896 deletions
diff --git a/module/plugins/Account.py b/module/plugins/Account.py
index e75fc0ecb..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
"""
@@ -38,9 +38,9 @@ class Account(Base):
__name__ = "Account"
__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 = 600
@@ -76,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)
diff --git a/module/plugins/AccountManager.py b/module/plugins/AccountManager.py
index 1de55effc..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
@@ -60,21 +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 ""
@@ -87,57 +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:])
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("\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"""
@@ -145,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)
@@ -166,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)
@@ -176,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 685ceac20..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
"""
@@ -28,9 +28,9 @@ class Container(Crypter):
__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):
@@ -38,19 +38,19 @@ 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)
@@ -58,7 +58,7 @@ class Container(Crypter):
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):
@@ -66,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 b2e6528e9..d1549fe80 100644
--- a/module/plugins/Crypter.py
+++ b/module/plugins/Crypter.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,23 +23,23 @@ 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"""
@@ -47,9 +47,9 @@ class Crypter(Plugin):
self.thread = thread
self.decrypt(self.pyfile)
-
+
self.createPackages()
-
+
def decrypt(self, pyfile):
raise NotImplementedError
@@ -59,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:
@@ -69,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 6f5abffed..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
"""
@@ -42,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")
@@ -108,7 +108,7 @@ class Hook(Base):
def __repr__(self):
return "<Hook %s>" % self.__name__
-
+
def setup(self):
""" more init stuff if needed """
pass
@@ -116,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):
@@ -128,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
@@ -158,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 4979d383b..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
"""
@@ -29,5 +29,5 @@ class Hoster(Plugin):
__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 584fcce49..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")
@@ -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
"""
@@ -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 e976b2c4a..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
"""
@@ -79,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:
@@ -371,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 3e8b33fbd..000000000
--- a/module/plugins/ReCaptcha.py
+++ /dev/null
@@ -1,22 +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 acfb6874a..8fb841a39 100644
--- a/module/plugins/accounts/AlldebridCom.py
+++ b/module/plugins/accounts/AlldebridCom.py
@@ -1,27 +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)
@@ -32,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 bbd81e10b..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/>.
-
- @author: zoidberg
-"""
-
-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 4fe01aa5b..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/>.
-
- @author: pking
-"""
-
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__ = ""
+ __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",
- post={"user": user, "password": data["password"], "submit": "Login"}, cookies=True)
+ 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 56cb5390b..a9e2274a2 100644
--- a/module/plugins/accounts/CramitIn.py
+++ b/module/plugins/accounts/CramitIn.py
@@ -1,14 +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 4f3189b0c..000000000
--- a/module/plugins/accounts/CyberlockerCh.py
+++ /dev/null
@@ -1,33 +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 bdd2000c9..414883228 100644
--- a/module/plugins/accounts/CzshareCom.py
+++ b/module/plugins/accounts/CzshareCom.py
@@ -1,22 +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/>.
-
- @author: zoidberg
-"""
-
from time import mktime, strptime
import re
@@ -24,31 +7,35 @@ 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>([\d ,]+) (KiB|MiB|GiB)</td>\s*<td>([^<]*)</td>\s*</tr>'
- CREDIT_LEFT_PATTERN = r'<tr class="active">\s*<td>([0-9 ,]+) (KiB|MiB|GiB)</td>\s*<td>([^<]*)</td>\s*</tr>'
def loadAccountInfo(self, user, req):
html = req.load("http://sdilej.cz/prehled_kreditu/")
- found = re.search(self.CREDIT_LEFT_PATTERN, html)
- if not found:
+ m = re.search(self.CREDIT_LEFT_PATTERN, html)
+ if m is None:
return {"validuntil": 0, "trafficleft": 0}
else:
- credits = float(found.group(1).replace(' ', '').replace(',', '.'))
- credits = credits * 1024 ** {'KiB': 0, 'MiB': 1, 'GiB': 2}[found.group(2)]
- validuntil = mktime(strptime(found.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={
"Prihlasit": "Prihlasit",
- "login-password": data["password"],
+ "login-password": data['password'],
"login-name": user
})
diff --git a/module/plugins/accounts/DdlstorageCom.py b/module/plugins/accounts/DdlstorageCom.py
deleted file mode 100644
index f3eebc59b..000000000
--- a/module/plugins/accounts/DdlstorageCom.py
+++ /dev/null
@@ -1,52 +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 dd714102f..878153fbf 100644
--- a/module/plugins/accounts/DebridItaliaCom.py
+++ b/module/plugins/accounts/DebridItaliaCom.py
@@ -1,48 +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: (.+?) \|'
- WALID_UNTIL_PATTERN = r"Premium valid till: (?P<D>[^|]+) \|"
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 427f5c34d..ec23f7a51 100644
--- a/module/plugins/accounts/DepositfilesCom.py
+++ b/module/plugins/accounts/DepositfilesCom.py
@@ -1,47 +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/>.
-
- @author: mkaay
-"""
-
import re
+
from time import strptime, mktime
from module.plugins.Account import Account
class DepositfilesCom(Account):
- __name__ = "DepositfilesCom"
- __version__ = "0.2"
- __type__ = "account"
+ __name__ = "DepositfilesCom"
+ __type__ = "account"
+ __version__ = "0.31"
+
__description__ = """Depositfiles.com account plugin"""
- __author_name__ = ("mkaay", "stickell")
- __author_mail__ = ("mkaay@mkaay.de", "l.stickell@yahoo.it")
+ __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("http://depositfiles.com/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):
- req.load("http://depositfiles.com/de/gold/payment.php")
- src = req.load("http://depositfiles.com/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 16ce674e2..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/>.
-
- @author: zoidberg
-"""
-
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"
- __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>'
+class EasybytezCom(XFSAccount):
+ __name__ = "EasybytezCom"
+ __type__ = "account"
+ __version__ = "0.12"
- def loadAccountInfo(self, user, req):
- html = req.load("http://www.easybytez.com/?op=my_account", decode=True)
-
- validuntil = trafficleft = None
- premium = False
-
- found = re.search(self.VALID_UNTIL_PATTERN, html)
- if found:
- try:
- self.logDebug("Expire date: " + found.group(1))
- validuntil = mktime(strptime(found.group(1), "%d %B %Y"))
- except Exception, e:
- self.logError(e)
- if validuntil > mktime(gmtime()):
- premium = True
- trafficleft = -1
- else:
- found = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- if found:
- trafficleft = found.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/"})
+ __description__ = """EasyBytez.com account plugin"""
+ __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 e5c781068..000000000
--- a/module/plugins/accounts/EgoFilesCom.py
+++ /dev/null
@@ -1,42 +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 3fb0d7f50..c75f8ee33 100644
--- a/module/plugins/accounts/EuroshareEu.py
+++ b/module/plugins/accounts/EuroshareEu.py
@@ -1,22 +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/>.
-
- @author: zoidberg
-"""
-
from time import mktime, strptime
import re
@@ -24,32 +7,34 @@ 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):
self.relogin(user)
html = req.load("http://euroshare.eu/customer-zone/settings/")
- found = re.search('id="input_expire_date" value="(\d+\.\d+\.\d+ \d+:\d+)"', html)
- if found is None:
+ m = re.search('id="input_expire_date" value="(\d+\.\d+\.\d+ \d+:\d+)"', html)
+ if m is None:
premium, validuntil = False, -1
else:
premium = True
- validuntil = mktime(strptime(found.group(1), "%d.%m.%Y %H:%M"))
+ validuntil = mktime(strptime(m.group(1), "%d.%m.%Y %H:%M"))
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,
- "password": data["password"]
+ "password": data['password']
}, decode=True)
if u">Nesprávne prihlasovacie meno alebo heslo" in html:
diff --git a/module/plugins/accounts/FastixRu.py b/module/plugins/accounts/FastixRu.py
index dbfd1f33e..d33d611c9 100644
--- a/module/plugins/accounts/FastixRu.py
+++ b/module/plugins/accounts/FastixRu.py
@@ -5,30 +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:
+ data['api'] = api
+ if "error_code" in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/FastshareCz.py b/module/plugins/accounts/FastshareCz.py
index ba6105e6e..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/>.
-
- @author: zoidberg
-"""
-
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'My account\s*\((.+?)\)'
- CREDIT_PATTERN = r'(?:Kredit|Credit)\s*</td>\s*<td[^>]*>([\d. \w]+)&nbsp;'
def loadAccountInfo(self, user, req):
+ validuntil = None
+ trafficleft = None
+ premium = None
+
html = req.load("http://www.fastshare.cz/user", decode=True)
- found = re.search(self.CREDIT_PATTERN, html)
- if found:
- trafficleft = parseFileSize(found.group(1)) / 1024
- premium = True if trafficleft else False
+ m = re.search(self.CREDIT_PATTERN, html)
+ if m:
+ 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 6a11493d2..20053d895 100644
--- a/module/plugins/accounts/File4safeCom.py
+++ b/module/plugins/accounts/File4safeCom.py
@@ -1,17 +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 f2becb8c9..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/>.
-
- @author: zoidberg
-"""
-
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')
@@ -61,8 +48,8 @@ class FilecloudIo(Account):
if not hasattr(self, "form_data"):
self.form_data = {}
- self.form_data["username"] = user
- self.form_data["password"] = data['password']
+ self.form_data['username'] = user
+ self.form_data['password'] = data['password']
html = req.load('https://secure.filecloud.io/user-login_p.html',
post=self.form_data,
diff --git a/module/plugins/accounts/FilefactoryCom.py b/module/plugins/accounts/FilefactoryCom.py
index 0eded0edf..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,14 +9,18 @@ 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):
html = req.load("http://www.filefactory.com/account/")
@@ -38,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
@@ -46,12 +36,13 @@ 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")
html = req.load("http://www.filefactory.com/member/signin.php", post={
"loginEmail": user,
- "loginPassword": data["password"],
+ "loginPassword": data['password'],
"Submit": "Sign In"})
if req.lastEffectiveURL != "http://www.filefactory.com/account/":
diff --git a/module/plugins/accounts/FilejungleCom.py b/module/plugins/accounts/FilejungleCom.py
index 304f20040..a3ec7af64 100644
--- a/module/plugins/accounts/FilejungleCom.py
+++ b/module/plugins/accounts/FilejungleCom.py
@@ -1,22 +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/>.
-
- @author: zoidberg
-"""
-
import re
from time import mktime, strptime
@@ -24,35 +7,39 @@ 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">'
+
def loadAccountInfo(self, user, req):
html = req.load(self.URL + "dashboard.php")
- found = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- if found:
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+ if m:
premium = True
- validuntil = mktime(strptime(found.group(1), "%d %b %Y"))
+ validuntil = mktime(strptime(m.group(1), "%d %b %Y"))
else:
premium = False
validuntil = -1
return {"premium": premium, "trafficleft": -1, "validuntil": validuntil}
+
def login(self, user, data, req):
html = req.load(self.URL + "login.php", post={
"loginUserName": user,
- "loginUserPassword": data["password"],
+ "loginUserPassword": data['password'],
"loginFormSubmit": "Login",
"recaptcha_challenge_field": "",
"recaptcha_response_field": "",
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 28ddf2e3f..a845e7ba4 100644
--- a/module/plugins/accounts/FilerNet.py
+++ b/module/plugins/accounts/FilerNet.py
@@ -1,61 +1,52 @@
# -*- 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'
+
def loadAccountInfo(self, user, req):
- self.html = req.load("https://filer.net/profile")
+ html = req.load("https://filer.net/profile")
# Free user
- if re.search(self.FREE_PATTERN, self.html):
+ if re.search(self.FREE_PATTERN, html):
return {"premium": False, "validuntil": None, "trafficleft": None}
- until = re.search(self.WALID_UNTIL_PATTERN, self.html)
- traffic = re.search(self.TRAFFIC_PATTERN, self.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):
- self.html = req.load("https://filer.net/login")
- token = re.search(self.TOKEN_PATTERN, self.html).group(1)
- self.html = req.load("https://filer.net/login_check",
- post={"_username": user, "_password": data["password"],
+ html = req.load("https://filer.net/login")
+ token = re.search(self.TOKEN_PATTERN, html).group(1)
+ html = req.load("https://filer.net/login_check",
+ post={"_username": user, "_password": data['password'],
"_remember_me": "on", "_csrf_token": token, "_target_path": "https://filer.net/"})
- if 'Logout' not in self.html:
+ if 'Logout' not in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/FilerioCom.py b/module/plugins/accounts/FilerioCom.py
index 5f2164cf1..4c6755293 100644
--- a/module/plugins/accounts/FilerioCom.py
+++ b/module/plugins/accounts/FilerioCom.py
@@ -1,14 +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 794e80d84..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/>.
-
- @author: RaNaN
-"""
-
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 266935a9f..1cf2a3a3c 100644
--- a/module/plugins/accounts/FileserveCom.py
+++ b/module/plugins/accounts/FileserveCom.py
@@ -1,22 +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/>.
-
- @author: mkaay
-"""
-
from time import mktime, strptime
from module.plugins.Account import Account
@@ -24,35 +7,38 @@ 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"))
- return {"trafficleft": res["traffic"], "validuntil": validuntil}
+ if res['type'] == "premium":
+ validuntil = mktime(strptime(res['expireTime'], "%Y-%m-%d %H:%M:%S"))
+ return {"trafficleft": res['traffic'], "validuntil": validuntil}
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"]:
+ 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",
+ 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 869705313..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/>.
-
- @author: zoidberg
-"""
-
-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 6628db6b1..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/>.
-
- @author: RaNaN
-"""
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/")
- 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"))
+ 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"))
- traffic = r"Traffic verbleibend:</td>\s*<td>([^<]+)"
- traffic = re.search(traffic, page, re.MULTILINE)
- traffic = traffic.group(1).strip()
- traffic = self.parseTraffic(traffic)
+ except Exception:
+ pass
+
+ 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 955cc3c7f..3b9841630 100644
--- a/module/plugins/accounts/FreeWayMe.py
+++ b/module/plugins/accounts/FreeWayMe.py
@@ -1,33 +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/>.
-
- @author: Nicolas Giese
-"""
-
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):
status = self.getAccountStatus(user, req)
@@ -36,19 +21,21 @@ class FreeWayMe(Account):
self.logDebug(status)
account_info = {"validuntil": -1, "premium": False}
- if status["premium"] == "Free":
- account_info["trafficleft"] = int(status["guthaben"]) * 1024
- elif status["premium"] == "Spender":
- account_info["trafficleft"] = -1
- elif status["premium"] == "Flatrate":
- account_info = {"validuntil": int(status["Flatrate"]),
+ if status['premium'] == "Free":
+ account_info['trafficleft'] = self.parseTraffic(status['guthaben'] + "MB")
+ elif status['premium'] == "Spender":
+ account_info['trafficleft'] = -1
+ elif status['premium'] == "Flatrate":
+ account_info = {"validuntil": float(status['Flatrate']),
"trafficleft": -1,
"premium": True}
return account_info
+
def getpw(self, user):
- return self.accounts[user]["password"]
+ 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)
+ get={"id": 4, "user": user, "pass": self.accounts[user]['password']})
+ 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 cb2ad700c..2da45aac6 100644
--- a/module/plugins/accounts/FshareVn.py
+++ b/module/plugins/accounts/FshareVn.py
@@ -1,22 +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/>.
-
- @author: zoidberg
-"""
-
from time import mktime, strptime
from pycurl import REFERER
import re
@@ -25,30 +8,34 @@ from module.plugins.Account import Account
class FshareVn(Account):
- __name__ = "FshareVn"
- __version__ = "0.06"
- __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>'
+
def loadAccountInfo(self, user, req):
- self.html = req.load("http://www.fshare.vn/account_info.php", decode=True)
+ html = req.load("http://www.fshare.vn/account_info.php", decode=True)
- if re.search(self.LIFETIME_PATTERN, self.html):
+ if re.search(self.LIFETIME_PATTERN, html):
self.logDebug("Lifetime membership detected")
trafficleft = self.getTrafficLeft()
return {"validuntil": -1, "trafficleft": trafficleft, "premium": True}
- found = re.search(self.VALID_UNTIL_PATTERN, self.html)
- if found:
+ m = re.search(self.VALID_UNTIL_PATTERN, html)
+ if m:
premium = True
- validuntil = mktime(strptime(found.group(1), '%I:%M:%S %p %d-%m-%Y'))
+ validuntil = mktime(strptime(m.group(1), '%I:%M:%S %p %d-%m-%Y'))
trafficleft = self.getTrafficLeft()
else:
premium = False
@@ -57,18 +44,20 @@ 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")
- self.html = req.load('https://www.fshare.vn/login.php', post={
+ html = req.load('https://www.fshare.vn/login.php', post={
"login_password": data['password'],
"login_useremail": user,
- "url_refe": "https://www.fshare.vn/login.php"
+ "url_refe": "http://www.fshare.vn/index.php"
}, referer=True, decode=True)
- if not '<img alt="VIP"' in self.html:
+ if not re.search(r'<img\s+alt="VIP"', html):
self.wrongPassword()
+
def getTrafficLeft(self):
- found = re.search(self.TRAFFIC_LEFT_PATTERN, self.html)
- return float(found.group(1)) * 1024 ** {'k': 0, 'K': 0, 'M': 1, 'G': 2}[found.group(2)] if found else 0
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+ 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 b454cba7a..f978d2fa0 100644
--- a/module/plugins/accounts/Ftp.py
+++ b/module/plugins/accounts/Ftp.py
@@ -4,11 +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 b6c738715..dff2fe394 100644
--- a/module/plugins/accounts/HellshareCz.py
+++ b/module/plugins/accounts/HellshareCz.py
@@ -1,22 +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/>.
-
- @author: zoidberg
-"""
-
import re
import time
@@ -24,26 +7,29 @@ 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>'
+
def loadAccountInfo(self, user, req):
self.relogin(user)
html = req.load("http://www.hellshare.com/")
- found = re.search(self.CREDIT_LEFT_PATTERN, html)
- if found is None:
+ m = re.search(self.CREDIT_LEFT_PATTERN, html)
+ if m is None:
trafficleft = None
validuntil = None
premium = False
else:
- credit = found.group(1)
+ credit = m.group(1)
premium = True
try:
if "." in credit:
@@ -55,32 +41,33 @@ 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={
"login": "Log in",
- "password": data["password"],
+ "password": data['password'],
"username": user,
"perm_login": "on"
})
diff --git a/module/plugins/accounts/HotfileCom.py b/module/plugins/accounts/HotfileCom.py
deleted file mode 100644
index f6988542f..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/>.
-
- @author: mkaay, JoKoT3
-"""
-
-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 e2f236e41..07e46eb07 100644
--- a/module/plugins/accounts/Http.py
+++ b/module/plugins/accounts/Http.py
@@ -4,11 +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 e37c860a6..b8244a06d 100644
--- a/module/plugins/accounts/LetitbitNet.py
+++ b/module/plugins/accounts/LetitbitNet.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 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):
## DISABLED BECAUSE IT GET 'key exausted' EVEN IF VALID ##
# api_key = self.accounts[user]['password']
- # json_data = [api_key, ["key/info"]]
+ # 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':
@@ -40,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 63b9576d6..19986157b 100644
--- a/module/plugins/accounts/LinksnappyCom.py
+++ b/module/plugins/accounts/LinksnappyCom.py
@@ -7,12 +7,14 @@ 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):
data = self.getAccountData(user)
@@ -35,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 1fbe00ff7..a082b97af 100644
--- a/module/plugins/accounts/MegaDebridEu.py
+++ b/module/plugins/accounts/MegaDebridEu.py
@@ -1,49 +1,39 @@
# -*- 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"
+
def loadAccountInfo(self, user, req):
data = self.getAccountData(user)
jsonResponse = req.load(self.API_URL,
- get={'action': 'connectUser', 'login': user, 'password': data["password"]})
- response = json_loads(jsonResponse)
+ get={'action': 'connectUser', 'login': user, 'password': data['password']})
+ 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":
+ get={'action': 'connectUser', 'login': user, 'password': data['password']})
+ res = json_loads(jsonResponse)
+ if res['response_code'] != "ok":
self.wrongPassword()
diff --git a/module/plugins/accounts/MegaRapidCz.py b/module/plugins/accounts/MegaRapidCz.py
new file mode 100644
index 000000000..41da7ac73
--- /dev/null
+++ b/module/plugins/accounts/MegaRapidCz.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from time import mktime, strptime
+from module.plugins.Account import Account
+
+
+class MegaRapidCz(Account):
+ __name__ = "MegaRapidCz"
+ __type__ = "account"
+ __version__ = "0.34"
+
+ __description__ = """MegaRapid.cz account plugin"""
+ __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):
+ html = req.load("http://megarapid.cz/mujucet/", decode=True)
+
+ m = re.search(self.LIMITDL_PATTERN, html)
+ if m:
+ data = self.getAccountData(user)
+ data['options']['limitDL'] = [int(m.group(1))]
+
+ 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(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/")
+ if "Heslo:" in htm:
+ start = htm.index('id="inp_hash" name="hash" value="')
+ htm = htm[start + 33:]
+ hashes = htm[0:32]
+ htm = req.load("http://megarapid.cz/prihlaseni/",
+ post={"hash": hashes,
+ "login": user,
+ "pass1": data['password'],
+ "remember": 0,
+ "sbmt": u"Přihlásit"})
diff --git a/module/plugins/accounts/MegasharesCom.py b/module/plugins/accounts/MegasharesCom.py
index 59aefe374..6e0a4358e 100644
--- a/module/plugins/accounts/MegasharesCom.py
+++ b/module/plugins/accounts/MegasharesCom.py
@@ -7,15 +7,18 @@ 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>'
+
def loadAccountInfo(self, user, req):
#self.relogin(user)
html = req.load("http://d01.megashares.com/myms.php", decode=True)
@@ -32,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 2225261f0..6128cddc8 100644
--- a/module/plugins/accounts/MovReelCom.py
+++ b/module/plugins/accounts/MovReelCom.py
@@ -1,20 +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 #: after that time [in minutes] pyload will relogin the account
- info_threshold = 30 #: account data will be reloaded after this time
- MAIN_PAGE = "http://movreel.com/"
+ login_timeout = 60
+ info_threshold = 30
- 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 704b4ac78..000000000
--- a/module/plugins/accounts/MultiDebridCom.py
+++ /dev/null
@@ -1,46 +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
- self.html = req.load("http://multi-debrid.com/api.php",
- get={"user": user, "pass": data["password"]})
- self.logDebug('JSON data: ' + self.html)
- self.json_data = json_loads(self.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 cd2fd575c..878413007 100644
--- a/module/plugins/accounts/MultishareCz.py
+++ b/module/plugins/accounts/MultishareCz.py
@@ -1,46 +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/>.
-
- @author: zoidberg
-"""
+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="([^"]+)">'
+
def loadAccountInfo(self, user, req):
#self.relogin(user)
html = req.load("http://www.multishare.cz/profil/", decode=True)
- found = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- trafficleft = parseFileSize(found.group('S'), found.group('U')) / 1024 if found else 0
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+ 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 3d2b52470..15bad6966 100755
--- a/module/plugins/accounts/NetloadIn.py
+++ b/module/plugins/accounts/NetloadIn.py
@@ -1,22 +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/>.
-
- @author: mkaay
-"""
-
import re
from time import time
@@ -24,17 +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/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 19fcea67a..4d90e1b25 100644
--- a/module/plugins/accounts/OboomCom.py
+++ b/module/plugins/accounts/OboomCom.py
@@ -2,49 +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"]
+ 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}
+
+ userData = accountData['user']
+
+ 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 b10e34314..2f1c914c1 100644
--- a/module/plugins/accounts/OneFichierCom.py
+++ b/module/plugins/accounts/OneFichierCom.py
@@ -1,46 +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'Your Premium Status will end the (\d+/\d+/\d+)'
- VALID_UNTIL_PATTERN = r'You are a premium user until (?P<d>\d{2})/(?P<m>\d{2})/(?P<y>\d{4})'
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
- def login(self, user, data, req):
+ return {'validuntil': validuntil, 'trafficleft': trafficleft, 'premium': premium or False}
- req.http.c.setopt(REFERER, "http://1fichier.com/login.pl?lg=en")
- html = req.load("http://1fichier.com/login.pl?lg=en", post={
- "mail": user,
- "pass": data["password"],
- "Login": "Login"})
+ def login(self, user, data, req):
+ req.http.c.setopt(REFERER, "https://1fichier.com/login.pl?lg=en")
+
+ 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 eab20480f..fb9732986 100644
--- a/module/plugins/accounts/OverLoadMe.py
+++ b/module/plugins/accounts/OverLoadMe.py
@@ -5,29 +5,32 @@ 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":
+ if data['membership'] == "Free":
return {"premium": False}
- account_info = {"validuntil": data["expirationunix"], "trafficleft": -1}
+ 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()
+ get={"user": user, "auth": data['password']}).strip()
data = json_loads(jsondata)
- if data["err"] == 1:
+ if data['err'] == 1:
self.wrongPassword()
diff --git a/module/plugins/accounts/Premium4Me.py b/module/plugins/accounts/Premium4Me.py
deleted file mode 100644
index c80f40f5c..000000000
--- a/module/plugins/accounts/Premium4Me.py
+++ /dev/null
@@ -1,27 +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 1da5d9002..c1abde309 100644
--- a/module/plugins/accounts/PremiumizeMe.py
+++ b/module/plugins/accounts/PremiumizeMe.py
@@ -6,12 +6,14 @@ 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):
# Get user data from premiumize.me
@@ -20,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)
@@ -35,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 5a69a7f66..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/>.
-
- @author: zoidberg
-"""
-
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)
- found = re.search(r'Stav kreditu: <strong>(.+?)</strong>', html)
- if found:
- trafficleft = parseFileSize(found.group(1)) / 1024
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+ if m:
+ 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 49a294d14..813453c03 100644
--- a/module/plugins/accounts/RPNetBiz.py
+++ b/module/plugins/accounts/RPNetBiz.py
@@ -5,20 +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}
@@ -29,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 c008a0db3..2899d5a68 100644
--- a/module/plugins/accounts/RapidgatorNet.py
+++ b/module/plugins/accounts/RapidgatorNet.py
@@ -1,36 +1,22 @@
# -*- 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/>.
-
- @author: zoidberg
-"""
-
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'
+
def loadAccountInfo(self, user, req):
try:
sid = self.getAccountData(user).get('SID')
@@ -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 17d7f0e08..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/>.
-
- @author: mkaay
-"""
-
-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 494941aef..577a6c8f6 100644
--- a/module/plugins/accounts/RarefileNet.py
+++ b/module/plugins/accounts/RarefileNet.py
@@ -1,14 +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 86ad18085..48b17df5f 100644
--- a/module/plugins/accounts/RealdebridCom.py
+++ b/module/plugins/accounts/RealdebridCom.py
@@ -6,28 +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 c4aa85484..00a45dedd 100644
--- a/module/plugins/accounts/RehostTo.py
+++ b/module/plugins/accounts/RehostTo.py
@@ -4,32 +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})
+
+ traffic, valid = html.split(",")
- account_info = {"trafficleft": int(traffic) * 1024,
- "validuntil": int(valid),
- "long_ses": long_ses,
- "ses": ses}
+ 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/ReloadCc.py b/module/plugins/accounts/ReloadCc.py
deleted file mode 100644
index af23d9936..000000000
--- a/module/plugins/accounts/ReloadCc.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from module.plugins.Account import Account
-
-from module.common.json_layer import json_loads
-
-from module.network.HTTPRequest import BadHeader
-
-
-class ReloadCc(Account):
- __name__ = "ReloadCc"
- __version__ = "0.3"
- __type__ = "account"
- __description__ = """Reload.cc account plugin"""
-
- __author_name__ = "Reload Team"
- __author_mail__ = "hello@reload.cc"
-
- def loadAccountInfo(self, user, req):
-
- # Get user data from reload.cc
- status = self.getAccountStatus(user, req)
-
- # Parse account info
- account_info = {"validuntil": float(status['msg']['expires']),
- "pwdhash": status['msg']['hash'],
- "trafficleft": -1}
-
- return account_info
-
- def login(self, user, data, req):
-
- # Get user data from reload.cc
- status = self.getAccountStatus(user, req)
-
- if not status:
- raise Exception("There was an error upon logging in to Reload.cc!")
-
- # Check if user and password are valid
- if status['status'] != "ok":
- self.wrongPassword()
-
- def getAccountStatus(self, user, req):
- # Use reload.cc API v1 to retrieve account info and return the parsed json answer
- query_params = dict(
- via='pyload',
- v=1,
- get_traffic='true',
- user=user
- )
-
- try:
- query_params.update(dict(hash=self.infos[user]['pwdhash']))
- except Exception:
- query_params.update(dict(pwd=self.accounts[user]['password']))
-
- try:
- answer = req.load("http://api.reload.cc/login", get=query_params)
- except BadHeader, e:
- if e.code == 400:
- raise Exception("There was an unknown error within the Reload.cc plugin.")
- elif e.code == 401:
- self.wrongPassword()
- elif e.code == 402:
- self.expired(user)
- elif e.code == 403:
- raise Exception("Your account is disabled. Please contact the Reload.cc support!")
- elif e.code == 409:
- self.empty(user)
- elif e.code == 503:
- self.logInfo("Reload.cc is currently in maintenance mode! Please check again later.")
- self.wrongPassword()
- return None
-
- return json_loads(answer)
diff --git a/module/plugins/accounts/RyushareCom.py b/module/plugins/accounts/RyushareCom.py
index 6a15c4c82..ca476366b 100644
--- a/module/plugins/accounts/RyushareCom.py
+++ b/module/plugins/accounts/RyushareCom.py
@@ -1,21 +1,25 @@
# -*- 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)]
+
+
+ HOSTER_DOMAIN = "ryushare.com"
- MAIN_PAGE = "http://ryushare.com/"
def login(self, user, data, req):
req.lastURL = "http://ryushare.com/login.python"
html = req.load("http://ryushare.com/login.python",
- post={"login": user, "password": data["password"], "op": "login"})
+ post={"login": user, "password": data['password'], "op": "login"})
if 'Incorrect Login or Password' in html or '>Error<' in html:
self.wrongPassword()
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/ShareRapidCom.py b/module/plugins/accounts/ShareRapidCom.py
deleted file mode 100644
index 38150e5cf..000000000
--- a/module/plugins/accounts/ShareRapidCom.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-from time import mktime, strptime
-from module.plugins.Account import Account
-
-
-class ShareRapidCom(Account):
- __name__ = "ShareRapidCom"
- __version__ = "0.33"
- __type__ = "account"
- __description__ = """ShareRapid account plugin"""
- __author_name__ = ("MikyWoW", "zoidberg")
- __author_mail__ = ("mikywow@seznam.cz", "zoidberg@mujmail.cz")
-
- login_timeout = 60
-
- def loadAccountInfo(self, user, req):
- src = req.load("http://sharerapid.cz/mujucet/", decode=True)
-
- found = re.search(ur'<td>Max. počet paralelních stahování: </td><td>(\d+)', src)
- if found:
- data = self.getAccountData(user)
- data["options"]["limitDL"] = [int(found.group(1))]
-
- found = re.search(ur'<td>Paušální stahování aktivní. Vyprší </td><td><strong>(.*?)</strong>', src)
- if found:
- validuntil = mktime(strptime(found.group(1), "%d.%m.%Y - %H:%M"))
- return {"premium": True, "trafficleft": -1, "validuntil": validuntil}
-
- found = re.search(r'<tr><td>Kredit</td><td>(.*?) GiB', src)
- if found:
- trafficleft = float(found.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://sharerapid.cz/prihlaseni/", cookies=True)
- if "Heslo:" in htm:
- start = htm.index('id="inp_hash" name="hash" value="')
- htm = htm[start + 33:]
- hashes = htm[0:32]
- htm = req.load("http://sharerapid.cz/prihlaseni/",
- post={"hash": hashes,
- "login": user,
- "pass1": data["password"],
- "remember": 0,
- "sbmt": u"Přihlásit"}, cookies=True)
diff --git a/module/plugins/accounts/ShareonlineBiz.py b/module/plugins/accounts/ShareonlineBiz.py
index f188fc580..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/>.
-
- @author: mkaay
-"""
-
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 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 getUserAPI(self, user, req):
- return req.load("http://api.share-online.biz/account.php",
- {"username": user, "password": self.accounts[user]["password"], "act": "userDetails"})
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 1e6d66806..465757457 100644
--- a/module/plugins/accounts/SimplyPremiumCom.py
+++ b/module/plugins/accounts/SimplyPremiumCom.py
@@ -1,33 +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.Account import Account
from module.common.json_layer import json_loads
+from module.plugins.Account import Account
class SimplyPremiumCom(Account):
- __name__ = "SimplyPremiumCom"
- __version__ = "0.01"
- __type__ = "account"
- __description__ = """Simply-Premium.Com account plugin"""
- __author_name__ = ("EvolutionClip")
- __author_mail__ = ("evolutionclip@live.de")
+ __name__ = "SimplyPremiumCom"
+ __type__ = "account"
+ __version__ = "0.02"
+
+ __description__ = """Simply-Premium.com account plugin"""
+ __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)
@@ -35,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")
@@ -50,9 +40,9 @@ class SimplyPremiumCom(Account):
if data['password'] == '' or data['password'] == '0':
post_data = {"key": user}
else:
- post_data = {"login_name": user, "login_pass": data["password"]}
+ post_data = {"login_name": user, "login_pass": data['password']}
- self.html = req.load("http://www.simply-premium.com/login.php", post=post_data)
+ html = req.load("http://www.simply-premium.com/login.php", post=post_data)
- if 'logout' not in self.html:
+ if 'logout' not in html:
self.wrongPassword()
diff --git a/module/plugins/accounts/SimplydebridCom.py b/module/plugins/accounts/SimplydebridCom.py
index c07702105..406534364 100644
--- a/module/plugins/accounts/SimplydebridCom.py
+++ b/module/plugins/accounts/SimplydebridCom.py
@@ -6,26 +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"]
+ 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 529e2131f..2b08c67cd 100644
--- a/module/plugins/accounts/StahnuTo.py
+++ b/module/plugins/accounts/StahnuTo.py
@@ -1,50 +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/>.
-
- @author: zoidberg
-"""
-
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")]
- #login_timeout = 60
def loadAccountInfo(self, user, req):
html = req.load("http://www.stahnu.to/")
- found = re.search(r'>VIP: (\d+.*)<', html)
- trafficleft = parseFileSize(found.group(1)) * 1024 if found else 0
+ m = re.search(r'>VIP: (\d+.*)<', html)
+ 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={
"username": user,
- "password": data["password"],
+ "password": data['password'],
"submit": "Login"})
if not '<a href="logout.php">' in html:
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 19ffaf1e5..f87d234a7 100644
--- a/module/plugins/accounts/TurbobitNet.py
+++ b/module/plugins/accounts/TurbobitNet.py
@@ -1,22 +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/>.
-
- @author: zoidberg
-"""
-
import re
from time import mktime, strptime
@@ -24,34 +7,35 @@ 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")]
- #login_timeout = 60
def loadAccountInfo(self, user, req):
html = req.load("http://turbobit.net")
- found = re.search(r'<u>Turbo Access</u> to ([0-9.]+)', html)
- if found:
+ m = re.search(r'<u>Turbo Access</u> to ([\d.]+)', html)
+ if m:
premium = True
- validuntil = mktime(strptime(found.group(1), "%d.%m.%Y"))
+ validuntil = mktime(strptime(m.group(1), "%d.%m.%Y"))
else:
premium = False
validuntil = -1
return {"premium": premium, "trafficleft": -1, "validuntil": validuntil}
+
def login(self, user, data, req):
req.cj.setCookie("turbobit.net", "user_lang", "en")
html = req.load("http://turbobit.net/user/login", post={
"user[login]": user,
- "user[pass]": data["password"],
+ "user[pass]": data['password'],
"user[submit]": "Login"})
if not '<div class="menu-item user-name">' in html:
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 6b1067f28..7236a4fa8 100644
--- a/module/plugins/accounts/UlozTo.py
+++ b/module/plugins/accounts/UlozTo.py
@@ -2,42 +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 .*?title="[^"]*?GB = ([\d.]+) MB"'
- TRAFFIC_LEFT_PATTERN = r'<li class="menu-kredit"><a href="/kredit" title="[^"]*?GB = ([0-9.]+) 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)
- found = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- trafficleft = int(float(found.group(1).replace(' ', '').replace(',', '.')) * 1000 * 1.048) if found else 0
- self.premium = True if trafficleft else False
+ m = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+
+ 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}
- return {"validuntil": -1, "trafficleft": trafficleft}
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 2b647a49c..f5db3f888 100644
--- a/module/plugins/accounts/UnrestrictLi.py
+++ b/module/plugins/accounts/UnrestrictLi.py
@@ -1,30 +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 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):
json_data = req.load('http://unrestrict.li/api/jdownloader/user.php?format=json')
@@ -35,21 +23,22 @@ 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"],
+ post_data = {"username": user, "password": data['password'],
"remember_me": "remember", "signin": "Sign in"}
- self.html = req.load("https://unrestrict.li/sign_in", post=post_data)
+ html = req.load("https://unrestrict.li/sign_in", post=post_data)
- if 'sign_out' not in self.html:
+ if 'sign_out' not in html:
self.wrongPassword()
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 02f31c544..c09726799 100644
--- a/module/plugins/accounts/UploadedTo.py
+++ b/module/plugins/accounts/UploadedTo.py
@@ -1,22 +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/>.
-
- @author: mkaay
-"""
-
import re
from time import time
@@ -24,45 +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
-
- 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()
+ premium = True if re.search(self.PREMIUM_PATTERN, html) else False
- traffic = int(self.parseTraffic(raw_traffic))
+ m = re.search(self.VALID_UNTIL_PATTERN, html, re.M)
+ if m:
+ expiredate = m.group(1).lower().strip()
- 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 8adcff4ac..1e30b3771 100644
--- a/module/plugins/accounts/UploadheroCom.py
+++ b/module/plugins/accounts/UploadheroCom.py
@@ -8,21 +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:
@@ -30,9 +32,10 @@ class UploadheroCom(Account):
return account_info
+
def login(self, user, data, req):
- page = req.load("http://uploadhero.co/lib/connexion.php",
- post={"pseudo_login": user, "password_login": data["password"]})
+ 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 f0395c13a..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/>.
-
- @author: mkaay
-"""
+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 3757ae0aa..299a0acc2 100644
--- a/module/plugins/accounts/UptoboxCom.py
+++ b/module/plugins/accounts/UptoboxCom.py
@@ -1,16 +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/Vipleech4uCom.py b/module/plugins/accounts/Vipleech4uCom.py
deleted file mode 100644
index 1e8463456..000000000
--- a/module/plugins/accounts/Vipleech4uCom.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# -*- coding: utf-8 -*-
-import re
-from time import mktime, strptime
-
-from module.plugins.Account import Account
-
-
-class Vipleech4uCom(Account):
- __name__ = "Vipleech4uCom"
- __version__ = "0.1"
- __type__ = "account"
- __description__ = """Vipleech4u.com account plugin"""
- __author_name__ = ("Kagenoshin")
- __author_mail__ = ("kagenoshin@gmx.ch")
-
- STATUS_PATTERN = re.compile(r'status.*?<\s*?strong\s*?>[^<]*?vip[^<]*?<', re.I)
- VALIDUNTIL_PATTERN = re.compile(r'valid\s*?until.*?<\s*?strong\s*?>([^<]*?)<', re.I)
-
- def loadAccountInfo(self, user, req):
- response = req.load("http://vipleech4u.com", decode=True)
- status = self.STATUS_PATTERN.search(response)
-
- validuntil = self.VALIDUNTIL_PATTERN.search(response)
- if validuntil:
- validuntil = validuntil.group(1)
-
- if status and validuntil:
- print status
- print validuntil
- return {"trafficleft": -1, "validuntil": mktime(strptime("%s 23:59" % validuntil, "%d-%m-%Y %H:%M"))}
- else:
- return {"premium": False}
-
- def login(self, user, data, req):
- self.loginname = user
- self.password = data["password"]
- post_data = {'action': 'login', 'user': self.loginname, 'pass': self.password}
- req.load("http://vipleech4u.com/login.php")
- response = req.load("http://vipleech4u.com/login.php", post=post_data, decode=True)
- if 'Username or Password are incorrect' in response:
- self.wrongPassword()
diff --git a/module/plugins/accounts/WarserverCz.py b/module/plugins/accounts/WarserverCz.py
deleted file mode 100644
index a5acf5e52..000000000
--- a/module/plugins/accounts/WarserverCz.py
+++ /dev/null
@@ -1,68 +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/>.
-
- @author: zoidberg
-"""
-
-import re
-
-from module.plugins.Account import Account
-from module.utils import parseFileSize
-
-
-class WarserverCz(Account):
- __name__ = "WarserverCz"
- __version__ = "0.02"
- __type__ = "account"
- __description__ = """Warserver.cz account plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
- VALID_UNTIL_PATTERN = ur'<li>Neomezené stahování do: <strong>(.+?)<'
- TRAFFIC_LEFT_PATTERN = ur'<li>Kredit: <strong>(.+?)<'
-
- DOMAIN = "http://www.warserver.cz"
-
- def loadAccountInfo(self, user, req):
- html = req.load("%s/uzivatele/prehled" % self.DOMAIN, decode=True)
-
- validuntil = trafficleft = None
- premium = False
-
- found = re.search(self.VALID_UNTIL_PATTERN, html)
- if found:
- self.logDebug("VALID_UNTIL", found.group(1))
- try:
- #validuntil = mktime(strptime(found.group(1), "%d %B %Y"))
- premium = True
- trafficleft = -1
- except Exception, e:
- self.logError(e)
-
- found = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- if found:
- self.logDebug("TRAFFIC_LEFT", found.group(1))
- trafficleft = parseFileSize((found.group(1).replace("&thinsp;", ""))) // 1024
- premium = True if trafficleft > 1 << 18 else False
-
- return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}
-
- def login(self, user, data, req):
- html = req.load('%s/uzivatele/prihlaseni?do=prihlaseni-submit' % self.DOMAIN,
- post={"username": user, "password": data['password'], "send": u"Přihlásit"}, decode=True)
-
- if '<p class="chyba">' in html:
- self.wrongPassword()
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 75aae25b9..92a6bfedf 100644
--- a/module/plugins/accounts/YibaishiwuCom.py
+++ b/module/plugins/accounts/YibaishiwuCom.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/>.
-
- @author: zoidberg
-"""
-
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 = {(.*?)}'
+
def loadAccountInfo(self, user, req):
#self.relogin(user)
html = req.load("http://115.com/", decode=True)
- found = re.search(self.ACCOUNT_INFO_PATTERN, html, re.S)
- premium = True if (found and 'is_vip: 1' in found.group(1)) else False
- validuntil = trafficleft = (-1 if found else 0)
+ m = re.search(self.ACCOUNT_INFO_PATTERN, html, re.S)
+ premium = True if (m and 'is_vip: 1' in m.group(1)) else False
+ 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 1eb90801a..e8e3431e3 100644
--- a/module/plugins/accounts/ZeveraCom.py
+++ b/module/plugins/accounts/ZeveraCom.py
@@ -6,12 +6,14 @@ 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):
data = self.getAPIData(req)
@@ -19,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"]
+ self.password = data['password']
if self.getAPIData(req) == "No traffic":
self.wrongPassword()
+
def getAPIData(self, req, just_header=False, **kwargs):
get_data = {
'cmd': 'accountinfo',
@@ -39,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 2d0837257..244cf6a2a 100644
--- a/module/plugins/captcha/GigasizeCom.py
+++ b/module/plugins/captcha/GigasizeCom.py
@@ -1,20 +1,24 @@
# -*- coding: utf-8 -*-
-from captcha import OCR
+from module.plugins.captcha.captcha import OCR
+
class GigasizeCom(OCR):
+ __name__ = "GigasizeCom"
+ __type__ = "ocr"
+ __version__ = "0.10"
+
+ __description__ = """Gigasize.com ocr plugin"""
+ __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)
self.run_tesser(True, False, False, True)
return self.result_captcha
-
-if __name__ == '__main__':
- ocr = GigasizeCom()
- import urllib
- urllib.urlretrieve('http://www.gigasize.com/randomImage.php', "gigasize_tmp.jpg")
-
- print ocr.get_captcha('gigasize_tmp.jpg')
diff --git a/module/plugins/captcha/LinksaveIn.py b/module/plugins/captcha/LinksaveIn.py
index 8ce26fbac..56cbd58a0 100644
--- a/module/plugins/captcha/LinksaveIn.py
+++ b/module/plugins/captcha/LinksaveIn.py
@@ -1,19 +1,32 @@
# -*- coding: utf-8 -*-
-from captcha import OCR
-import Image
-from os import sep
-from os.path import dirname
-from os.path import abspath
+try:
+ from PIL import Image
+except ImportError:
+ import Image
+
from glob import glob
+from os import sep
+from os.path import abspath, dirname
+
+from module.plugins.captcha.captcha import OCR
class LinksaveIn(OCR):
- __name__ = "LinksaveIn"
+ __name__ = "LinksaveIn"
+ __type__ = "ocr"
+ __version__ = "0.10"
+
+ __description__ = """Linksave.in ocr plugin"""
+ __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
@@ -41,6 +54,7 @@ class LinksaveIn(OCR):
self.pixels = self.image.load()
self.result_captcha = ''
+
def get_bg(self):
stat = {}
cstat = {}
@@ -71,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")
@@ -99,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()
@@ -120,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()
@@ -139,11 +156,3 @@ class LinksaveIn(OCR):
final += self.result_captcha
return final
-
-if __name__ == '__main__':
- import urllib
- ocr = LinksaveIn()
- testurl = "http://linksave.in/captcha/cap.php?hsh=2229185&code=ZzHdhl3UffV3lXTH5U4b7nShXj%2Bwma1vyoNBcbc6lcc%3D"
- urllib.urlretrieve(testurl, ocr.data_dir+"captcha.gif")
-
- print ocr.get_captcha(ocr.data_dir+'captcha.gif')
diff --git a/module/plugins/captcha/NetloadIn.py b/module/plugins/captcha/NetloadIn.py
index 733fe99db..28eb18fb5 100644
--- a/module/plugins/captcha/NetloadIn.py
+++ b/module/plugins/captcha/NetloadIn.py
@@ -1,12 +1,22 @@
# -*- coding: utf-8 -*-
-from captcha import OCR
+from module.plugins.captcha.captcha import OCR
+
class NetloadIn(OCR):
- __name__ = "NetloadIn"
+ __name__ = "NetloadIn"
+ __type__ = "ocr"
+ __version__ = "0.10"
+
+ __description__ = """Netload.in ocr plugin"""
+ __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()
@@ -17,10 +27,3 @@ class NetloadIn(OCR):
self.result_captcha = self.result_captcha.replace(" ", "")[:4] # cut to 4 numbers
return self.result_captcha
-
-if __name__ == '__main__':
- import urllib
- ocr = NetloadIn()
- urllib.urlretrieve("http://netload.in/share/includes/captcha.php", "captcha.png")
-
- print ocr.get_captcha('captcha.png')
diff --git a/module/plugins/captcha/ShareonlineBiz.py b/module/plugins/captcha/ShareonlineBiz.py
index 0c87b636d..8210e8859 100644
--- a/module/plugins/captcha/ShareonlineBiz.py
+++ b/module/plugins/captcha/ShareonlineBiz.py
@@ -1,31 +1,23 @@
# -*- 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 captcha import OCR
+from module.plugins.captcha.captcha import OCR
+
class ShareonlineBiz(OCR):
- __name__ = "ShareonlineBiz"
+ __name__ = "ShareonlineBiz"
+ __type__ = "ocr"
+ __version__ = "0.10"
+
+ __description__ = """Shareonline.biz ocr plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
+
def __init__(self):
OCR.__init__(self)
- def get_captcha(self, image):
+
+ def get_captcha(self, image):
self.load_image(image)
self.to_greyscale()
self.image = self.image.resize((160, 50))
@@ -45,9 +37,3 @@ class ShareonlineBiz(OCR):
return final
#tesseract at 60%
-
-if __name__ == '__main__':
- import urllib
- ocr = ShareonlineBiz()
- urllib.urlretrieve("http://www.share-online.biz/captcha.php", "captcha.jpeg")
- print ocr.get_captcha('captcha.jpeg')
diff --git a/module/plugins/captcha/captcha.py b/module/plugins/captcha/captcha.py
index 7e4dec697..0f233ec00 100644
--- a/module/plugins/captcha/captcha.py
+++ b/module/plugins/captcha/captcha.py
@@ -1,56 +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.10"
+
+ __description__ = """OCR base plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
- __name__ = "OCR"
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"""
@@ -61,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 = ["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)
@@ -110,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
@@ -136,6 +136,7 @@ class OCR(object):
else:
self.pixels[x, y] = 0
+
def clean(self, allowed):
pixels = self.pixels
@@ -143,19 +144,28 @@ class OCR(object):
for x in xrange(w):
for y in xrange(h):
- if pixels[x, y] == 255: continue
- # no point in processing white pixels since we only want to remove black pixel
+ if pixels[x, y] == 255:
+ continue
+ # No point in processing white pixels since we only want to remove black pixel
count = 0
try:
- if pixels[x-1, y-1] != 255: count += 1
- if pixels[x-1, y] != 255: count += 1
- if pixels[x-1, y + 1] != 255: count += 1
- if pixels[x, y + 1] != 255: count += 1
- if pixels[x + 1, y + 1] != 255: count += 1
- if pixels[x + 1, y] != 255: count += 1
- if pixels[x + 1, y-1] != 255: count += 1
- if pixels[x, y-1] != 255: count += 1
+ if pixels[x-1, y-1] != 255:
+ count += 1
+ if pixels[x-1, y] != 255:
+ count += 1
+ if pixels[x-1, y + 1] != 255:
+ count += 1
+ if pixels[x, y + 1] != 255:
+ count += 1
+ if pixels[x + 1, y + 1] != 255:
+ count += 1
+ if pixels[x + 1, y] != 255:
+ count += 1
+ if pixels[x + 1, y-1] != 255:
+ count += 1
+ if pixels[x, y-1] != 255:
+ count += 1
except:
pass
@@ -167,10 +177,12 @@ class OCR(object):
# second pass: this time set all 1's to 255 (white)
for x in xrange(w):
for y in xrange(h):
- if pixels[x, y] == 1: pixels[x, y] = 255
+ if pixels[x, y] == 1:
+ pixels[x, y] = 255
self.pixels = pixels
+
def derotate_by_average(self):
"""rotate by checking each angle and guess most suitable"""
@@ -245,6 +257,7 @@ class OCR(object):
self.pixels = pixels
+
def split_captcha_letters(self):
captcha = self.image
started = False
@@ -262,13 +275,16 @@ class OCR(object):
firstX = x
lastX = x
- if y > bottomY: bottomY = y
- if y < topY: topY = y
- if x > lastX: lastX = x
+ if y > bottomY:
+ bottomY = y
+ if y < topY:
+ topY = y
+ if x > lastX:
+ lastX = x
black_pixel_in_col = True
- if black_pixel_in_col == False and started == True:
+ if black_pixel_in_col is False and started is True:
rect = (firstX, topY, lastX, bottomY)
new_captcha = captcha.crop(rect)
@@ -281,8 +297,8 @@ class OCR(object):
return letters
- def correct(self, values, var=None):
+ def correct(self, values, var=None):
if var:
result = var
else:
@@ -300,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 8aec97f6a..bca535175 100644
--- a/module/plugins/container/CCF.py
+++ b/module/plugins/container/CCF.py
@@ -1,24 +1,31 @@
# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
import re
+
+from os import makedirs
+from os.path import exists
from urllib2 import build_opener
+from MultipartPostHandler import MultipartPostHandler
+
from module.plugins.Container import Container
-from module.lib.MultipartPostHandler import MultipartPostHandler
+from module.utils import save_join
-from os import makedirs
-from os.path import exists, 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):
+ def decrypt(self, pyfile):
infile = pyfile.url.replace("\n", "")
opener = build_opener(MultipartPostHandler)
@@ -28,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.packages.append((tempdlc_name, [tempdlc_name], tempdlc_name))
+ 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 79678954d..c6173ad73 100644
--- a/module/plugins/container/LinkList.py
+++ b/module/plugins/container/LinkList.py
@@ -1,18 +1,24 @@
# -*- coding: utf-8 -*-
import codecs
-from module.utils import fs_encode
+
from module.plugins.Container import Container
+from module.utils import fs_encode
+
class LinkList(Container):
- __name__ = "LinkList"
+ __name__ = "LinkList"
__version__ = "0.12"
+
__pattern__ = r'.+\.txt'
- __description__ = """Read link lists in txt format"""
__config__ = [("clear", "bool", "Clear Linklist after adding", False),
("encoding", "string", "File encoding (default utf-8)", "")]
- __author_name__ = ("spoob", "jeix")
- __author_mail__ = ("spoob@pyload.org", "jeix@hasnomail.com")
+
+ __description__ = """Read link lists in txt format"""
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org"),
+ ("jeix", "jeix@hasnomail.com")]
+
def decrypt(self, pyfile):
try:
@@ -20,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)
@@ -33,7 +36,8 @@ class LinkList(Container):
for link in links:
link = link.strip()
- if not link: continue
+ if not link:
+ continue
if link.startswith(";"):
continue
@@ -61,7 +65,7 @@ class LinkList(Container):
txt = open(file_name, 'wb')
txt.close()
except:
- self.log.warning(_("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 42296f2d5..0c43f0e6c 100644
--- a/module/plugins/container/RSDF.py
+++ b/module/plugins/container/RSDF.py
@@ -1,24 +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.21"
+ __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')
@@ -27,21 +35,22 @@ 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()))
data = data.splitlines()
- links = []
for link in data:
+ if not link:
+ continue
link = base64.b64decode(link)
link = obj.decrypt(link)
decryptedUrl = link.replace('CCF: ', '')
- links.append(decryptedUrl)
+ self.urls.append(decryptedUrl)
- self.log.debug("%s: adding package %s with %d links" % (self.__name__,pyfile.package().name,len(links)))
- self.packages.append((pyfile.package().name, 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 7139c26a6..c70a849b6 100644
--- a/module/plugins/crypter/BitshareComFolder.py
+++ b/module/plugins/crypter/BitshareComFolder.py
@@ -1,30 +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"
- __type__ = "crypter"
+ __name__ = "BitshareComFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
__pattern__ = r'http://(?:www\.)?bitshare\.com/\?d=\w+'
- __version__ = "0.01"
+ __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 8923cfc32..bc58fbf1c 100644
--- a/module/plugins/crypter/C1neonCom.py
+++ b/module/plugins/crypter/C1neonCom.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?c1neon.com/.*?'
+ __name__ = "C1neonCom"
+ __type__ = "crypter"
__version__ = "0.05"
+
+ __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 529ec6918..133e5a005 100644
--- a/module/plugins/crypter/ChipDe.py
+++ b/module/plugins/crypter/ChipDe.py
@@ -5,20 +5,25 @@ from module.plugins.Crypter import Crypter
class ChipDe(Crypter):
- __name__ = "ChipDe"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?chip.de/video/.*\.html'
- __version__ = "0.1"
+ __name__ = "ChipDe"
+ __type__ = "crypter"
+ __version__ = "0.10"
+
+ __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:
- url = re.search(r'"(http://video.chip.de/\d+?/.*)"', self.html).group(1)
- self.logDebug('The file URL is %s' % url)
+ f = re.search(r'"(http://video\.chip\.de/.+)"', self.html)
except:
- self.fail('Failed to find the URL')
-
- self.packages.append((pyfile.package().name, [url], pyfile.package().folder))
+ self.fail(_("Failed to find the URL"))
+ else:
+ self.urls = [f.group(1)]
+ 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 e64e63534..57bb339ff 100644
--- a/module/plugins/crypter/CrockoComFolder.py
+++ b/module/plugins/crypter/CrockoComFolder.py
@@ -1,15 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?crocko.com/f/.*'
+ __name__ = "CrockoComFolder"
+ __type__ = "crypter"
__version__ = "0.01"
+
+ __pattern__ = r'http://(?:www\.)?crocko\.com/f/.+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
__description__ = """Crocko.com folder decrypter plugin"""
- __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 6f8fbaa1a..2cf4e9f62 100644
--- a/module/plugins/crypter/CryptItCom.py
+++ b/module/plugins/crypter/CryptItCom.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?crypt-it\.com/(s|e|d|c)/[\w]+'
+ __name__ = "CryptItCom"
+ __type__ = "crypter"
__version__ = "0.11"
+
+ __pattern__ = r'http://(?:www\.)?crypt-it\.com/(s|e|d|c)/\w+'
+ __config__ = []
+
__description__ = """Crypt-it.com decrypter plugin"""
- __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 d1ba8335c..5623a4093 100644
--- a/module/plugins/crypter/CzshareComFolder.py
+++ b/module/plugins/crypter/CzshareComFolder.py
@@ -5,27 +5,28 @@ from module.plugins.Crypter import Crypter
class CzshareComFolder(Crypter):
- __name__ = "CzshareComFolder"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?(czshare|sdilej)\.(com|cz)/folders/.*'
- __version__ = "0.2"
+ __name__ = "CzshareComFolder"
+ __type__ = "crypter"
+ __version__ = "0.20"
+
+ __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>'
- #NEXT_PAGE_PATTERN = r'<a class="next " href="/([^"]+)">&nbsp;</a>'
+
def decrypt(self, pyfile):
html = self.load(pyfile.url)
- new_links = []
- found = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
- if found is None: self.fail("Parse error (FOLDER)")
- new_links.extend(re.findall(self.LINK_PATTERN, found.group(1)))
+ m = re.search(self.FOLDER_PATTERN, html, re.S)
+ if m is None:
+ self.error(_("FOLDER_PATTERN not found"))
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ self.urls.extend(re.findall(self.LINK_PATTERN, m.group(1)))
diff --git a/module/plugins/crypter/DDLMusicOrg.py b/module/plugins/crypter/DDLMusicOrg.py
index 27cff3f9d..55181e9ad 100644
--- a/module/plugins/crypter/DDLMusicOrg.py
+++ b/module/plugins/crypter/DDLMusicOrg.py
@@ -1,30 +1,37 @@
# -*- coding: utf-8 -*-
import re
+
from time import sleep
from module.plugins.Crypter import Crypter
class DDLMusicOrg(Crypter):
- __name__ = "DDLMusicOrg"
- __type__ = "crypter"
+ __name__ = "DDLMusicOrg"
+ __type__ = "crypter"
+ __version__ = "0.30"
+
__pattern__ = r'http://(?:www\.)?ddl-music\.org/captcha/ddlm_cr\d\.php\?\d+\?\d+'
- __version__ = "0.3"
+ __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)
@@ -34,11 +41,11 @@ 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)
if m:
- self.packages.append((pyfile.package().name, [m.group(1)], pyfile.package().folder))
+ self.urls = [m.group(1)]
else:
self.retry()
diff --git a/module/plugins/crypter/DailymotionBatch.py b/module/plugins/crypter/DailymotionBatch.py
index 5c0dd9cec..8d4cb64df 100644
--- a/module/plugins/crypter/DailymotionBatch.py
+++ b/module/plugins/crypter/DailymotionBatch.py
@@ -1,24 +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/>.
-
- @author: Walter Purcaro
-"""
+import re
from urlparse import urljoin
-import re
from module.common.json_layer import json_loads
from module.plugins.Crypter import Crypter
@@ -26,19 +10,25 @@ from module.utils import save_join
class DailymotionBatch(Crypter):
- __name__ = "DailymotionBatch"
- __type__ = "crypter"
- __pattern__ = r'https?://(?:www\.)?dailymotion\.com/((playlists/)?(?P<TYPE>playlist|user)/)?(?P<ID>[\w^_]+)(?(TYPE)|#)'
+ __name__ = "DailymotionBatch"
+ __type__ = "crypter"
__version__ = "0.01"
+
+ __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):
url = urljoin("https://api.dailymotion.com/", ref)
page = self.load(url, get=req)
return json_loads(page)
+
def getPlaylistInfo(self, id):
ref = "playlist/" + id
req = {"fields": "name,owner.screenname"}
@@ -47,10 +37,11 @@ class DailymotionBatch(Crypter):
if "error" in playlist:
return
- name = playlist["name"]
- owner = playlist["owner.screenname"]
+ name = playlist['name']
+ 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}
@@ -59,16 +50,18 @@ class DailymotionBatch(Crypter):
if "error" in user:
return
- for playlist in user["list"]:
- yield playlist["id"]
+ for playlist in user['list']:
+ yield playlist['id']
- if user["has_more"]:
+ if user['has_more']:
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}
@@ -77,20 +70,22 @@ class DailymotionBatch(Crypter):
if "error" in playlist:
return
- for video in playlist["list"]:
- yield video["url"]
+ for video in playlist['list']:
+ yield video['url']
- if playlist["has_more"]:
+ if playlist['has_more']:
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")
@@ -102,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 04ef152fc..a5602d6c6 100644
--- a/module/plugins/crypter/DataHuFolder.py
+++ b/module/plugins/crypter/DataHuFolder.py
@@ -1,54 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?data.hu/dir/\w+'
- __version__ = "0.03"
+ __name__ = "DataHuFolder"
+ __type__ = "crypter"
+ __version__ = "0.06"
+
+ __pattern__ = r'http://(?:www\.)?data\.hu/dir/\w+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
__description__ = """Data.hu folder decrypter plugin"""
- __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>'
+ NAME_PATTERN = ur'<title>(?P<N>.+) Let\xf6lt\xe9se</title>'
- LINK_PATTERN = r"<a href='(http://data\.hu/get/.+)' target='_blank'>\1</a>"
- TITLE_PATTERN = ur'<title>(?P<title>.+) 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 6501de822..e02e77fda 100644
--- a/module/plugins/crypter/DdlstorageComFolder.py
+++ b/module/plugins/crypter/DdlstorageComFolder.py
@@ -1,29 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?ddlstorage.com/folder/\w{10}'
- __version__ = "0.02"
+class DdlstorageComFolder(DeadCrypter):
+ __name__ = "DdlstorageComFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
+ __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 = '<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 74d199e12..147f093c3 100644
--- a/module/plugins/crypter/DepositfilesComFolder.py
+++ b/module/plugins/crypter/DepositfilesComFolder.py
@@ -1,15 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?depositfiles.com/folders/\w+'
+ __name__ = "DepositfilesComFolder"
+ __type__ = "crypter"
__version__ = "0.01"
+
+ __pattern__ = r'http://(?:www\.)?depositfiles\.com/folders/\w+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
__description__ = """Depositfiles.com folder decrypter plugin"""
- __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 4b6309c17..0729c8cb6 100644
--- a/module/plugins/crypter/Dereferer.py
+++ b/module/plugins/crypter/Dereferer.py
@@ -1,35 +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
+ __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)]
-from module.plugins.Crypter import Crypter
-
-
-class Dereferer(Crypter):
- __name__ = "Dereferer"
- __type__ = "crypter"
- __pattern__ = r'https?://([^/]+)/.*?(?P<url>(ht|f)tps?(://|%3A%2F%2F).*)'
- __version__ = "0.1"
__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.core.files.addLinks([urllib.unquote(link).rstrip('+')], pyfile.package().id)
+ __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 dbe5bf705..a99ed0be9 100644
--- a/module/plugins/crypter/DlProtectCom.py
+++ b/module/plugins/crypter/DlProtectCom.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 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/>.
-#
-# @author: Walter Purcaro
-###############################################################################
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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?dl-protect\.com/((en|fr)/)?(?P<ID>\w+)'
+ __name__ = "DlProtectCom"
+ __type__ = "crypter"
__version__ = "0.01"
+
+ __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'
- OFFLINE_PATTERN = ">Unfortunately, the link you are looking for is not found"
def getLinks(self):
# Direct link with redirect
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": ""}
@@ -55,20 +46,23 @@ class DlProtectCom(SimpleCrypter):
post_req.update({"i": b64time, "submitform": "Decrypt+link"})
if ">Password :" in self.html:
- post_req["pwd"] = self.getPassword()
+ post_req['pwd'] = self.getPassword()
if ">Security Code" in self.html:
captcha_id = re.search(r'/captcha\.php\?uid=(.+?)"', self.html).group(1)
captcha_url = "http://www.dl-protect.com/captcha.php?uid=" + captcha_id
captcha_code = self.decryptCaptcha(captcha_url, imgtype="gif")
- post_req["secure"] = captcha_code
+ post_req['secure'] = captcha_code
self.html = self.load(self.pyfile.url, post=post_req)
for errmsg in (">The password is incorrect", ">The security code is incorrect"):
if errmsg in self.html:
- self.fail(errmsg[1:])
+ 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 42a38e98f..d656cde4c 100644
--- a/module/plugins/crypter/DontKnowMe.py
+++ b/module/plugins/crypter/DontKnowMe.py
@@ -1,22 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?dontknow.me/at/\?.+$'
- __version__ = "0.1"
- __description__ = """DontKnow.me decrypter plugin"""
- __author_name__ = "selaux"
- __author_mail__ = ""
-
- LINK_PATTERN = r"http://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)]
- def decrypt(self, pyfile):
- link = re.findall(self.LINK_PATTERN, pyfile.url)[0]
- self.core.files.addLinks([urllib.unquote(link)], pyfile.package().id)
+ __description__ = """DontKnow.me decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("selaux", "")]
diff --git a/module/plugins/crypter/DownloadVimeoCom.py b/module/plugins/crypter/DownloadVimeoCom.py
deleted file mode 100644
index 3e137bab1..000000000
--- a/module/plugins/crypter/DownloadVimeoCom.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-import HTMLParser
-from module.plugins.Crypter import Crypter
-
-
-class DownloadVimeoCom(Crypter):
- __name__ = 'DownloadVimeoCom'
- __type__ = 'crypter'
- __pattern__ = r'(?:http://vimeo\.com/\d*|http://smotri\.com/video/view/\?id=.*)'
- __version__ = '0.1'
- __description__ = """Vimeo.com decrypter plugin"""
- __author_name__ = "4Christopher"
- __author_mail__ = "4Christopher@gmx.de"
-
- BASE_URL = 'http://downloadvimeo.com'
-
- def decrypt(self, pyfile):
- self.package = pyfile.package()
- html = self.load('%s/generate?url=%s' % (self.BASE_URL, pyfile.url))
- h = HTMLParser.HTMLParser()
- try:
- f = re.search(r'cmd quality="(?P<quality>[^"]+?)">\s*?(?P<URL>[^<]*?)</cmd>', html)
- except:
- self.logDebug('Failed to find the URL')
- else:
- url = h.unescape(f.group('URL'))
- self.logDebug('Quality: %s, URL: %s' % (f.group('quality'), url))
- self.packages.append((self.package.name, [url], self.package.folder))
diff --git a/module/plugins/crypter/DuckCryptInfo.py b/module/plugins/crypter/DuckCryptInfo.py
index f44bac2e9..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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?duckcrypt.info/(folder|wait|link)/(\w+)/?(\w*)'
+ __name__ = "DuckCryptInfo"
+ __type__ = "crypter"
__version__ = "0.02"
+
+ __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))
- #found = re.search(self.TIMER_PATTERN, src)
- #if found:
- # self.logDebug("Sleeping for" % found.group(1))
- # self.setWait(int(found.group(1)) ,False)
- found = re.match(self.__pattern__, url)
- if not found:
- self.fail('Weird error in link')
- if str(found.group(1)) == "link":
+
+ m = re.match(self.__pattern__, url)
+ if m is None:
+ self.fail(_("Weird error in link"))
+ if str(m.group(1)) == "link":
self.handleLink(url)
else:
- self.handleFolder(found)
+ self.handleFolder(m)
- def handleFolder(self, found):
- src = self.load("http://duckcrypt.info/ajax/auth.php?hash=" + str(found.group(2)))
- found = re.match(self.__pattern__, src)
- self.logDebug("Redirectet to " + str(found.group(0)))
- src = self.load(str(found.group(0)))
- soup = BeautifulSoup(src)
+ def handleFolder(self, m):
+ 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)))
+ 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 found - (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)
- link = soup.find("iframe")["src"]
- if not link:
- self.logDebug('no links found - (Plugin out of date?)')
- else:
- self.core.files.addLinks([link], self.pyfile.package().id)
+ html = self.load(url)
+ soup = BeautifulSoup(html)
+ self.urls = [soup.find("iframe")['src']]
+ if not self.urls:
+ self.logInfo(_("No link found"))
diff --git a/module/plugins/crypter/DuploadOrgFolder.py b/module/plugins/crypter/DuploadOrgFolder.py
index 4913bdf2e..066fbe3d7 100644
--- a/module/plugins/crypter/DuploadOrgFolder.py
+++ b/module/plugins/crypter/DuploadOrgFolder.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.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
-class DuploadOrgFolder(SimpleCrypter):
- __name__ = "DuploadOrgFolder"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?dupload\.org/folder/\d+/'
- __version__ = "0.01"
+class DuploadOrgFolder(DeadCrypter):
+ __name__ = "DuploadOrgFolder"
+ __type__ = "crypter"
+ __version__ = "0.02"
+
+ __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 b4a6284fc..04f9b853b 100644
--- a/module/plugins/crypter/EasybytezComFolder.py
+++ b/module/plugins/crypter/EasybytezComFolder.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
-
-
-class EasybytezComFolder(SimpleCrypter):
- __name__ = "EasybytezComFolder"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?easybytez\.com/users/(?P<ID>\d+/\d+)'
- __version__ = "0.05"
- __description__ = """Easybytez.com decrypter plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
-
- FILE_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 fbccf71aa..be3181793 100644
--- a/module/plugins/crypter/EmbeduploadCom.py
+++ b/module/plugins/crypter/EmbeduploadCom.py
@@ -6,48 +6,55 @@ from module.network.HTTPRequest import BadHeader
class EmbeduploadCom(Crypter):
- __name__ = "EmbeduploadCom"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?embedupload.com/\?d=.*'
+ __name__ = "EmbeduploadCom"
+ __type__ = "crypter"
__version__ = "0.02"
+
+ __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"""
- __config__ = [("preferedHoster", "str", "Prefered hoster list (bar-separated) ", "embedupload"),
- ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")]
- __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")>'
+
def decrypt(self, pyfile):
self.html = self.load(pyfile.url, decode=True)
tmp_links = []
- new_links = []
- found = re.findall(self.LINK_PATTERN, self.html)
- if found:
+ m = re.findall(self.LINK_PATTERN, self.html)
+ if m:
prefered_set = set(self.getConfig("preferedHoster").split('|'))
prefered_set = map(lambda s: s.lower().split('.')[0], prefered_set)
- print "PF", prefered_set
- tmp_links.extend([x[1] for x in found if x[0] in prefered_set])
- self.getLocation(tmp_links, new_links)
- if not new_links:
+ 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
- tmp_links.extend([x[1] for x in found if x[0] not in ignored_set])
- self.getLocation(tmp_links, new_links)
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ 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)
- def getLocation(self, tmp_links, new_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
+ return new_links
diff --git a/module/plugins/crypter/FilebeerInfoFolder.py b/module/plugins/crypter/FilebeerInfoFolder.py
index f5818e072..a3c7ee74c 100644
--- a/module/plugins/crypter/FilebeerInfoFolder.py
+++ b/module/plugins/crypter/FilebeerInfoFolder.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?filebeer\.info/(\d+~f).*'
+ __name__ = "FilebeerInfoFolder"
+ __type__ = "crypter"
__version__ = "0.02"
+
+ __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
new file mode 100644
index 000000000..83cce352d
--- /dev/null
+++ b/module/plugins/crypter/FilecloudIoFolder.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
+
+
+class FilecloudIoFolder(SimpleCrypter):
+ __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"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ LINK_PATTERN = r'href="(http://filecloud\.io/\w+)" title'
+ NAME_PATTERN = r'>(?P<N>.+?) - filecloud\.io<'
+
+
+getInfo = create_getInfo(FilecloudIoFolder)
diff --git a/module/plugins/crypter/FilecryptCc.py b/module/plugins/crypter/FilecryptCc.py
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 aece1a01d..26e28acbd 100644
--- a/module/plugins/crypter/FilefactoryComFolder.py
+++ b/module/plugins/crypter/FilefactoryComFolder.py
@@ -1,45 +1,31 @@
# -*- coding: utf-8 -*-
-import re
-from module.plugins.Crypter import Crypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
-class FilefactoryComFolder(Crypter):
- __name__ = "FilefactoryComFolder"
- __type__ = "crypter"
- __pattern__ = r'(http://(?:www\.)?filefactory\.com/f/\w+).*'
- __version__ = "0.1"
+class FilefactoryComFolder(SimpleCrypter):
+ __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__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
- FOLDER_PATTERN = r'<table class="items" cellspacing="0" cellpadding="0">(.*?)</table>'
- LINK_PATTERN = r'<td class="name"><a href="([^"]+)">'
- PAGINATOR_PATTERN = r'<div class="list">\s*<label>Pages</label>\s*<ul>(.*?)</ul>\s*</div>'
- NEXT_PAGE_PATTERN = r'<li class="current">.*?</li>\s*<li class=""><a href="([^"]+)">'
-
- def decrypt(self, pyfile):
- url_base = re.match(self.__pattern__, pyfile.url).group(1)
- html = self.load(url_base)
-
- new_links = []
- for i in xrange(1, 100):
- self.logInfo("Fetching links from page %i" % i)
- found = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
- if found is None: self.fail("Parse error (FOLDER)")
-
- new_links.extend(re.findall(self.LINK_PATTERN, found.group(1)))
-
- try:
- paginator = re.search(self.PAGINATOR_PATTERN, html, re.DOTALL).group(1)
- next_page = re.search(self.NEXT_PAGE_PATTERN, paginator).group(1)
- html = self.load("%s/%s" % (url_base, next_page))
- except Exception, e:
- break
- else:
- self.logInfo("Limit of 99 pages reached, aborting")
-
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
+
+ LINK_PATTERN = r'<td><a href="([^"]+)">'
+ NAME_PATTERN = r'<h1>Files in <span>(?P<N>.+)</span></h1>'
+ PAGES_PATTERN = r'data-paginator-totalPages="(\d+)"'
+
+ 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
new file mode 100644
index 000000000..00db173bb
--- /dev/null
+++ b/module/plugins/crypter/FilerNetFolder.py
@@ -0,0 +1,29 @@
+import re
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
+
+
+class FilerNetFolder(SimpleCrypter):
+ __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"""
+ __license__ = "GPLv3"
+ __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
+
+
+ LINK_PATTERN = r'href="(/get/\w{16})">(?!<)'
+ NAME_PATTERN = r'<h3>(?P<N>.+?) - <small'
+
+
+ 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 c3c8b58fe..e6b35fd36 100644
--- a/module/plugins/crypter/FileserveComFolder.py
+++ b/module/plugins/crypter/FileserveComFolder.py
@@ -6,28 +6,33 @@ from module.plugins.Crypter import Crypter
class FileserveComFolder(Crypter):
- __name__ = "FileserveComFolder"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?fileserve.com/list/\w+'
+ __name__ = "FileserveComFolder"
+ __type__ = "crypter"
__version__ = "0.11"
+
+ __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">'
+
def decrypt(self, pyfile):
html = self.load(pyfile.url)
new_links = []
- folder = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
- if folder is None: self.fail("Parse error (FOLDER)")
+ folder = re.search(self.FOLDER_PATTERN, html, re.S)
+ if folder is None:
+ self.error(_("FOLDER_PATTERN not found"))
new_links.extend(re.findall(self.LINK_PATTERN, folder.group(1)))
if new_links:
- self.core.files.addLinks(map(lambda s: "http://fileserve.com%s" % s, new_links), pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ self.urls = [map(lambda s: "http://fileserve.com%s" % s, new_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 f4f09e878..16ebdda37 100644
--- a/module/plugins/crypter/FilestubeCom.py
+++ b/module/plugins/crypter/FilestubeCom.py
@@ -1,30 +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"
- __type__ = "crypter"
+ __name__ = "FilestubeCom"
+ __type__ = "crypter"
+ __version__ = "0.05"
+
__pattern__ = r'http://(?:www\.)?filestube\.(?:com|to)/\w+'
- __version__ = "0.03"
+ __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://[^\"]+)'
+ NAME_PATTERN = r'<h1\s*> (?P<N>.+) download\s*</h1>'
+
- LINK_PATTERN = r"<a class=\"file-link-main(?: noref)?\" [^>]* href=\"(http://[^\"]+)"
- TITLE_PATTERN = r"<h1\s*> (?P<title>.+) download\s*</h1>"
+getInfo = create_getInfo(FilestubeCom)
diff --git a/module/plugins/crypter/FiletramCom.py b/module/plugins/crypter/FiletramCom.py
index 8cdf32ad5..76530c589 100644
--- a/module/plugins/crypter/FiletramCom.py
+++ b/module/plugins/crypter/FiletramCom.py
@@ -1,30 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?filetram.com/[^/]+/.+'
- __version__ = "0.01"
+ __name__ = "FiletramCom"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
+ __pattern__ = r'http://(?:www\.)?filetram\.com/[^/]+/.+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
__description__ = """Filetram.com decrypter plugin"""
- __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://.+)'
+ NAME_PATTERN = r'<title>(?P<N>.+?) - Free Download'
+
- LINK_PATTERN = r"\s+(http://.+)"
- TITLE_PATTERN = r"<title>(?P<title>[^<]+) - Free Download[^<]*</title>"
+getInfo = create_getInfo(FiletramCom)
diff --git a/module/plugins/crypter/FiredriveComFolder.py b/module/plugins/crypter/FiredriveComFolder.py
new file mode 100644
index 000000000..7d3a357fd
--- /dev/null
+++ b/module/plugins/crypter/FiredriveComFolder.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
+
+
+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"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+getInfo = create_getInfo(FiredriveComFolder)
diff --git a/module/plugins/crypter/FourChanOrg.py b/module/plugins/crypter/FourChanOrg.py
index 010451c46..d6c5c86cc 100644
--- a/module/plugins/crypter/FourChanOrg.py
+++ b/module/plugins/crypter/FourChanOrg.py
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
+#
+# Based on 4chandl by Roland Beermann (https://gist.github.com/enkore/3492599)
import re
@@ -6,20 +8,20 @@ from module.plugins.Crypter import Crypter
class FourChanOrg(Crypter):
- # Based on 4chandl by Roland Beermann
- # https://gist.github.com/enkore/3492599
- __name__ = "FourChanOrg"
- __type__ = "crypter"
- __version__ = "0.3"
- __pattern__ = r'http://(?:www\.)?boards\.4chan.org/\w+/res/(\d+)'
+ __name__ = "FourChanOrg"
+ __type__ = "crypter"
+ __version__ = "0.30"
+
+ __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"""
+ __license__ = "GPLv3"
+ __authors__ = []
+
def decrypt(self, pyfile):
pagehtml = self.load(pyfile.url)
-
images = set(re.findall(r'(images\.4chan\.org/[^/]*/src/[^"<]*)', pagehtml))
- urls = []
- for image in images:
- urls.append("http://" + image)
-
- self.core.files.addLinks(urls, pyfile.package().id)
+ self.urls = ["http://" + image for image in images]
diff --git a/module/plugins/crypter/FreakhareComFolder.py b/module/plugins/crypter/FreakhareComFolder.py
index c5df7ff17..7c1b7de2b 100644
--- a/module/plugins/crypter/FreakhareComFolder.py
+++ b/module/plugins/crypter/FreakhareComFolder.py
@@ -1,36 +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/>. #
-############################################################################
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class FreakhareComFolder(SimpleCrypter):
- __name__ = "FreakhareComFolder"
- __type__ = "crypter"
+ __name__ = "FreakhareComFolder"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
__pattern__ = r'http://(?:www\.)?freakshare\.com/folder/.+'
- __version__ = "0.01"
+ __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">'
+ NAME_PATTERN = r'Folder:</b> (?P<N>.+)'
+ PAGES_PATTERN = r'Pages: +(\d+)'
- 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+)'
def loadPage(self, page_n):
if not hasattr(self, 'f_id') and not hasattr(self, 'f_md5'):
@@ -44,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 e5c9c3d21..c33c9ff64 100644
--- a/module/plugins/crypter/FreetexthostCom.py
+++ b/module/plugins/crypter/FreetexthostCom.py
@@ -1,36 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?freetexthost\.com/\w+'
+ __name__ = "FreetexthostCom"
+ __type__ = "crypter"
__version__ = "0.01"
+
+ __pattern__ = r'http://(?:www\.)?freetexthost\.com/\w+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
__description__ = """Freetexthost.com decrypter plugin"""
- __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)
- if not m:
- self.fail('Unable to extract links | Plugin may be out-of-date')
+ m = re.search(r'<div id="contentsinner">\s*(.+)<div class="viewcount">', self.html, re.S)
+ if m is None:
+ self.error(_("Unable to extract links"))
links = m.group(1)
return links.strip().split("<br />\r\n")
+
+
+getInfo = create_getInfo(FreetexthostCom)
diff --git a/module/plugins/crypter/FshareVnFolder.py b/module/plugins/crypter/FshareVnFolder.py
index 6e67905d9..474364e40 100644
--- a/module/plugins/crypter/FshareVnFolder.py
+++ b/module/plugins/crypter/FshareVnFolder.py
@@ -1,15 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?fshare.vn/folder/.*'
+ __name__ = "FshareVnFolder"
+ __type__ = "crypter"
__version__ = "0.01"
+
+ __pattern__ = r'http://(?:www\.)?fshare\.vn/folder/.+'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
__description__ = """Fshare.vn folder decrypter plugin"""
- __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 15f0a9a8c..d548a3375 100644
--- a/module/plugins/crypter/GooGl.py
+++ b/module/plugins/crypter/GooGl.py
@@ -1,40 +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"
- __type__ = "crypter"
- __pattern__ = r'https?://(?:www\.)?goo\.gl/\w+'
+ __name__ = "GooGl"
+ __type__ = "crypter"
__version__ = "0.01"
+
+ __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"
- 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.core.files.addLinks([rep['longUrl']], pyfile.package().id)
+ 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 c6773b3f0..a347e4232 100644
--- a/module/plugins/crypter/HoerbuchIn.py
+++ b/module/plugins/crypter/HoerbuchIn.py
@@ -2,52 +2,59 @@
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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?hoerbuch\.in/(wp/horbucher/\d+/.+/|tp/out.php\?.+|protection/folder_\d+\.html)'
- __version__ = "0.6"
+ __name__ = "HoerbuchIn"
+ __type__ = "crypter"
+ __version__ = "0.60"
+
+ __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")
+
def decrypt(self, pyfile):
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}):
package = "%s (%s)" % (abookname, a.previousSibling.previousSibling.text[:-1])
- links = self.decryptFolder(a["href"])
+ links = self.decryptFolder(a['href'])
- self.packages.append((package, links, pyfile.package().folder))
+ self.packages.append((package, links, package))
else:
- links = self.decryptFolder(pyfile.url)
+ self.urls = self.decryptFolder(pyfile.url)
- self.packages.append((pyfile.package().name, links, pyfile.package().folder))
def decryptFolder(self, url):
m = self.protection.search(url)
- if not m:
- self.fail("Bad URL")
+ if m is None:
+ 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 3a4a9d70a..000000000
--- a/module/plugins/crypter/HotfileFolderCom.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-
-from module.plugins.Crypter import Crypter
-
-
-class HotfileFolderCom(Crypter):
- __name__ = "HotfileFolderCom"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?hotfile.com/list/\w+/\w+'
- __version__ = "0.1"
- __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.append((name, new_links, name))
diff --git a/module/plugins/crypter/ILoadTo.py b/module/plugins/crypter/ILoadTo.py
index 3a388d41f..f3415706d 100644
--- a/module/plugins/crypter/ILoadTo.py
+++ b/module/plugins/crypter/ILoadTo.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?iload\.to/go/\d+-[\w\.-]+/'
+ __name__ = "ILoadTo"
+ __type__ = "crypter"
__version__ = "0.11"
+
+ __pattern__ = r'http://(?:www\.)?iload\.to/go/\d+-[\w.-]+/'
+ __config__ = []
+
__description__ = """Iload.to decrypter plugin"""
- __author_name__ = "hzpz"
- __author_mail__ = ""
+ __license__ = "GPLv3"
+ __authors__ = [("hzpz", None)]
+
+
+getInfo = create_getInfo(ILoadTo)
diff --git a/module/plugins/crypter/ImgurComAlbum.py b/module/plugins/crypter/ImgurComAlbum.py
new file mode 100644
index 000000000..6c074f5f1
--- /dev/null
+++ b/module/plugins/crypter/ImgurComAlbum.py
@@ -0,0 +1,30 @@
+import re
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
+from module.utils import uniqify
+
+
+class ImgurComAlbum(SimpleCrypter):
+ __name__ = "ImgurComAlbum"
+ __type__ = "crypter"
+ __version__ = "0.51"
+
+ __pattern__ = r'https?://(?:www\.|m\.)?imgur\.com/(a|gallery|)/?\w{5,7}'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
+ __description__ = """Imgur.com decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com")]
+
+
+ NAME_PATTERN = r'(?P<N>.+?) - Imgur'
+ LINK_PATTERN = r'i\.imgur\.com/\w{7}s?\.(?:jpeg|jpg|png|gif|apng)'
+
+
+ def getLinks(self):
+ f = lambda url: "http://" + re.sub(r'(\w{7})s\.', r'\1.', url)
+ return uniqify(map(f, re.findall(self.LINK_PATTERN, self.html)))
+
+
+getInfo = create_getInfo(ImgurComAlbum)
diff --git a/module/plugins/crypter/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 8e994984b..56ecbc7f8 100644
--- a/module/plugins/crypter/LetitbitNetFolder.py
+++ b/module/plugins/crypter/LetitbitNetFolder.py
@@ -5,29 +5,29 @@ from module.plugins.Crypter import Crypter
class LetitbitNetFolder(Crypter):
- __name__ = "LetitbitNetFolder"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?letitbit.net/folder/\w+'
- __version__ = "0.1"
+ __name__ = "LetitbitNetFolder"
+ __type__ = "crypter"
+ __version__ = "0.10"
+
+ __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">'
+
def decrypt(self, pyfile):
html = self.load(pyfile.url)
- 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)")
-
- new_links.extend(re.findall(self.LINK_PATTERN, folder.group(0)))
+ self.error(_("FOLDER_PATTERN not found"))
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ self.urls.extend(re.findall(self.LINK_PATTERN, folder.group(0)))
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 85dde6c87..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"
+ __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)]
-class LinkSaveIn(Crypter):
- __name__ = "LinkSaveIn"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?linksave.in/(?P<id>\w+)$'
- __version__ = "2.01"
__description__ = """LinkSave.in decrypter plugin"""
- __author_name__ = "fragonib"
- __author_mail__ = "fragonib[AT]yahoo[DOT]es"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- # Constants
- _JK_KEY_ = "jk"
- _CRYPTED_KEY_ = "crypted"
- HOSTER_DOMAIN = "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']
+ COOKIES = [("linksave.in", "Linksave_Language", "english")]
- 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_DOMAIN, "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)
-
- # 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
+ OFFLINE_PATTERN = r'>(Error )?404 -'
diff --git a/module/plugins/crypter/LinkdecrypterCom.py b/module/plugins/crypter/LinkdecrypterCom.py
index a6e6faa40..91318eadf 100644
--- a/module/plugins/crypter/LinkdecrypterCom.py
+++ b/module/plugins/crypter/LinkdecrypterCom.py
@@ -1,52 +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/>.
-
- @author: zoidberg
-"""
-
import re
from module.plugins.Crypter import Crypter
class LinkdecrypterCom(Crypter):
- __name__ = "LinkdecrypterCom"
- __type__ = "crypter"
+ __name__ = "LinkdecrypterCom"
+ __type__ = "crypter"
__version__ = "0.27"
+
+ __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"'
CAPTCHA_PATTERN = r'<img class="captcha" src="(.+?)"(.*?)>'
REDIR_PATTERN = r'<i>(Click <a href="./">here</a> if your browser does not redirect you).</i>'
- def decrypt(self, pyfile):
+ def decrypt(self, pyfile):
self.passwords = self.getPassword().splitlines()
# API not working anymore
- new_links = self.decryptHTML()
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ self.urls = self.decryptHTML()
- 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,32 +44,32 @@ 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:
- found = re.search(self.TEXTAREA_PATTERN, self.html, flags=re.DOTALL)
- if found:
- return [x for x in found.group(1).splitlines() if '[LINK-ERROR]' not in x]
+ 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]
- found = re.search(self.CAPTCHA_PATTERN, self.html)
- if found:
- captcha_url = 'http://linkdecrypter.com/' + found.group(1)
- result_type = "positional" if "getPos" in found.group(2) else "textual"
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
+ if m:
+ captcha_url = 'http://linkdecrypter.com/' + m.group(1)
+ result_type = "positional" if "getPos" in m.group(2) else "textual"
- found = re.search(r"<p><i><b>([^<]+)</b></i></p>", self.html)
- msg = found.group(1) if found else ""
- self.logInfo("Captcha protected link", result_type, msg)
+ 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)
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 619a474f2..d899d58c7 100644
--- a/module/plugins/crypter/LixIn.py
+++ b/module/plugins/crypter/LixIn.py
@@ -6,53 +6,57 @@ from module.plugins.Crypter import Crypter
class LixIn(Crypter):
- __name__ = "LixIn"
- __type__ = "crypter"
- __pattern__ = r'http://(www.)?lix.in/(?P<id>.*)'
+ __name__ = "LixIn"
+ __type__ = "crypter"
__version__ = "0.22"
+
+ __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="(captcha_img\.php\?.*?)"'
+ SUBMIT_PATTERN = r'value=\'continue.*?\''
+ LINK_PATTERN = r'name="ifram" src="(.*?)"'
- CAPTCHA_PATTERN = '<img src="(?P<image>captcha_img.php\?.*?)"'
- SUBMIT_PATTERN = r"value='continue.*?'"
- LINK_PATTERN = r'name="ifram" src="(?P<link>.*?)"'
def decrypt(self, pyfile):
url = pyfile.url
- matches = re.match(self.__pattern__, url)
- if not matches:
- self.fail("couldn't identify file id")
+ m = re.match(self.__pattern__, url)
+ if m is None:
+ self.error(_("Unable to identify file ID"))
- id = matches.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)
- matches = re.search(self.SUBMIT_PATTERN, self.html)
- if not matches:
- self.fail("link doesn't seem valid")
+ m = re.search(self.SUBMIT_PATTERN, self.html)
+ if m is None:
+ self.error(_("Link doesn't seem valid"))
- matches = re.search(self.CAPTCHA_PATTERN, self.html)
- if matches:
- for _ in xrange(5):
- matches = re.search(self.CAPTCHA_PATTERN, self.html)
- if matches:
- self.logDebug("trying captcha")
- captcharesult = self.decryptCaptcha("http://lix.in/" + matches.group("image"))
- self.html = self.req.load(url, decode=True,
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
+ if m:
+ 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(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})
- matches = re.search(self.LINK_PATTERN, self.html)
- if not matches:
- self.fail("can't find destination url")
-
- new_link = matches.group("link")
- self.logDebug("Found link %s, adding to package" % new_link)
-
- self.packages.append((pyfile.package().name, [new_link], pyfile.package().name))
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ self.error(_("Unable to find destination url"))
+ else:
+ 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 a17d58884..3cac0fbf2 100644
--- a/module/plugins/crypter/LofCc.py
+++ b/module/plugins/crypter/LofCc.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?lof.cc/(.*)'
+ __name__ = "LofCc"
+ __type__ = "crypter"
__version__ = "0.21"
+
+ __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 8aa70e8ff..82c2d9719 100644
--- a/module/plugins/crypter/MBLinkInfo.py
+++ b/module/plugins/crypter/MBLinkInfo.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?mblink\.info/?\?id=(\d+)'
+ __name__ = "MBLinkInfo"
+ __type__ = "crypter"
__version__ = "0.03"
+
+ __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 46856229c..d1dc89518 100644
--- a/module/plugins/crypter/MediafireComFolder.py
+++ b/module/plugins/crypter/MediafireComFolder.py
@@ -7,51 +7,52 @@ from module.common.json_layer import json_loads
class MediafireComFolder(Crypter):
- __name__ = "MediafireComFolder"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?mediafire\.com/(folder/|\?sharekey=|\?\w{13}($|[/#]))'
+ __name__ = "MediafireComFolder"
+ __type__ = "crypter"
__version__ = "0.14"
+
+ __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 = '<meta property="og:url" content="http://www.mediafire.com/\?(\w+)"/>'
- def decrypt(self, pyfile):
- new_links = []
+ 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)
- found = re.search(self.FILE_URL_PATTERN, html)
- if found:
+ m = re.search(self.LINK_PATTERN, html)
+ if m:
# file page
- new_links.append("http://www.mediafire.com/file/%s" % found.group(1))
+ self.urls.append("http://www.mediafire.com/file/%s" % m.group(1))
else:
# folder page
- found = re.search(self.FOLDER_KEY_PATTERN, html)
- if found:
- folder_key = found.group(1)
+ m = re.search(self.FOLDER_KEY_PATTERN, html)
+ if m:
+ 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']:
- new_links.append("http://www.mediafire.com/file/%s" % link['quickkey'])
+ self.urls.append("http://www.mediafire.com/file/%s" % link['quickkey'])
else:
self.fail(json_resp['response']['message'])
elif result == 1:
self.offline()
else:
- new_links.append(url)
-
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ self.urls.append(url)
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 991e1e1ee..7d71950fd 100644
--- a/module/plugins/crypter/Movie2kTo.py
+++ b/module/plugins/crypter/Movie2kTo.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?movie2k\.to/(.*)\.html'
+ __name__ = "Movie2kTo"
+ __type__ = "crypter"
__version__ = "0.51"
+
+ __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 997d60862..5209ebf09 100644
--- a/module/plugins/crypter/MultiUpOrg.py
+++ b/module/plugins/crypter/MultiUpOrg.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 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/>.
-#
-# @author: Walter Purcaro
-###############################################################################
-
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"
- __type__ = "crypter"
- __pattern__ = r"http://(?:www\.)?multiup\.org/(en|fr)/(?P<TYPE>project|download|miror)/\w+(/\w+)?"
- __version__ = "0.01"
+ __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")]
+
+
+ NAME_PATTERN = r'<title>.*(?:Project|Projet|ownload|élécharger) (?P<N>.+?) (\(|- )'
- TITLE_PATTERN = r'<title>.*(Project|Projet|ownload|élécharger) (?P<title>.+?) (\(|- )'
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/.*)'
@@ -47,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 5e7051bad..fa1eb02d7 100644
--- a/module/plugins/crypter/MultiloadCz.py
+++ b/module/plugins/crypter/MultiloadCz.py
@@ -5,38 +5,38 @@ from module.plugins.Crypter import Crypter
class MultiloadCz(Crypter):
- __name__ = "MultiloadCz"
- __type__ = "crypter"
- __pattern__ = r'http://(?:[^/]*\.)?multiload.cz/(stahnout|slozka)/.*'
- __version__ = "0.4"
+ __name__ = "MultiloadCz"
+ __type__ = "crypter"
+ __version__ = "0.40"
+
+ __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"""
- __config__ = [("usedHoster", "str", "Prefered hoster list (bar-separated) ", ""),
- ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")]
- __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="([^"]+)">'
+
def decrypt(self, pyfile):
self.html = self.load(pyfile.url, decode=True)
- new_links = []
if re.match(self.__pattern__, pyfile.url).group(1) == "slozka":
- found = re.search(self.FOLDER_PATTERN, self.html)
- if found is not None:
- new_links.extend(found.group(1).split())
+ m = re.search(self.FOLDER_PATTERN, self.html)
+ if m:
+ self.urls.extend(m.group(1).split())
else:
- found = re.findall(self.LINK_PATTERN, self.html)
- if found:
+ m = re.findall(self.LINK_PATTERN, self.html)
+ if m:
prefered_set = set(self.getConfig("usedHoster").split('|'))
- new_links.extend([x[1] for x in found if x[0] in prefered_set])
+ self.urls.extend([x[1] for x in m if x[0] in prefered_set])
- if not new_links:
+ if not self.urls:
ignored_set = set(self.getConfig("ignoredHoster").split('|'))
- new_links.extend([x[1] for x in found if x[0] not in ignored_set])
-
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ self.urls.extend([x[1] for x in m if x[0] not in ignored_set])
diff --git a/module/plugins/crypter/MultiuploadCom.py b/module/plugins/crypter/MultiuploadCom.py
index 677080772..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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?multiupload.com/(\w+)'
- __version__ = "0.01"
- __description__ = """MultiUpload.com decrypter plugin"""
- __config__ = [("preferedHoster", "str", "Prefered hoster list (bar-separated) ", "multiupload"),
- ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")]
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __pattern__ = r'http://(?:www\.)?multiupload\.(com|nl)/\w+'
+ __config__ = []
- ML_LINK_PATTERN = r'<div id="downloadbutton_" style=""><a href="([^"]+)"'
+ __description__ = """ MultiUpload.com decrypter plugin """
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- def decrypt(self, pyfile):
- self.html = self.load(pyfile.url)
- found = re.search(self.ML_LINK_PATTERN, self.html)
- ml_url = found.group(1) if found 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))
- }))
- new_links = []
-
- prefered_set = map(lambda s: s.lower().split('.')[0], set(self.getConfig("preferedHoster").split('|')))
-
- if ml_url and 'multiupload' in prefered_set:
- new_links.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:
- new_links.append(url)
-
- if not new_links:
- ignored_set = map(lambda s: s.lower().split('.')[0], set(self.getConfig("ignoredHoster").split('|')))
-
- if 'multiupload' not in ignored_set:
- new_links.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:
- new_links.append(url)
-
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- 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 eacd4aa8d..8b7214157 100644
--- a/module/plugins/crypter/NCryptIn.py
+++ b/module/plugins/crypter/NCryptIn.py
@@ -5,34 +5,40 @@ import binascii
import re
from Crypto.Cipher import AES
+
from module.plugins.Crypter import Crypter
from module.plugins.internal.CaptchaService import ReCaptcha
class NCryptIn(Crypter):
- __name__ = "NCryptIn"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?ncrypt.in/(?P<type>folder|link|frame)-([^/\?]+)'
- __version__ = "1.32"
+ __name__ = "NCryptIn"
+ __type__ = "crypter"
+ __version__ = "1.33"
+
+ __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")]
+
- # Constants
- _JK_KEY_ = "jk"
- _CRYPTED_KEY_ = "crypted"
+ JK_KEY = "jk"
+ CRYPTED_KEY = "crypted"
NAME_PATTERN = r'<meta name="description" content="(?P<N>[^"]+)"'
+
def setup(self):
self.package = None
- self.html = None
self.cleanedHtml = None
- self.links_source_order = ['cnl2', 'rsdf', 'ccf', 'dlc', 'web']
+ self.links_source_order = ["cnl2", "rsdf", "ccf", "dlc", "web"]
self.protection_type = None
- def decrypt(self, pyfile):
+ def decrypt(self, pyfile):
# Init
self.package = pyfile.package()
package_links = []
@@ -52,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)
@@ -69,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')
- return link_type in ('link', 'frame')
+ 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)>',
@@ -87,27 +95,30 @@ 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 found")
+ self.logDebug("File not m")
return False
return True
+
def isProtected(self):
- form_match = re.search(r'<form.*?name.*?protected.*?>(.*?)</form>', self.cleanedHtml, re.DOTALL)
- if form_match:
- form_content = form_match.group(1)
+ 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"):
- if keyword in form_content:
+ if keyword in content:
self.protection_type = keyword
self.logDebug("Links are %s protected" % self.protection_type)
return True
return False
+
def getPackageInfo(self):
m = re.search(self.NAME_PATTERN, self.html)
if m:
@@ -116,14 +127,14 @@ class NCryptIn(Crypter):
else:
name = self.package.name
folder = self.package.folder
- self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder))
+ 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:
@@ -139,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:
@@ -162,25 +173,24 @@ class NCryptIn(Crypter):
postData['submit_protected'] = 'Continue to folder'
return self.load(self.pyfile.url, post=postData, decode=True)
- def handleErrors(self):
+ 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):
+ def handleLinkSource(self, link_source_type):
# Check for JS engine
- require_js_engine = link_source_type in ('cnl2', 'rsdf', 'ccf', 'dlc')
+ require_js_engine = link_source_type in ("cnl2", "rsdf", "ccf", "dlc")
if require_js_engine and not self.js:
self.logDebug("No JS engine available, skip %s links" % link_source_type)
return []
@@ -190,15 +200,15 @@ class NCryptIn(Crypter):
return self.handleSingleLink()
if link_source_type == 'cnl2':
return self.handleCNL2()
- elif link_source_type in ('rsdf', 'ccf', 'dlc'):
+ elif link_source_type in ("rsdf", "ccf", "dlc"):
return self.handleContainer(link_source_type)
- elif link_source_type == 'web':
+ 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,24 +273,24 @@ 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
- jk_re = pattern % NCryptIn._JK_KEY_
+ jk_re = pattern % NCryptIn.JK_KEY
vjk = re.findall(jk_re, self.html)
# Get crypted
- crypted_re = pattern % NCryptIn._CRYPTED_KEY_
+ crypted_re = pattern % NCryptIn.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):
+ def _getLinks(self, crypted, jk):
# Get key
jreturn = self.js.eval("%s f()" % jk)
self.logDebug("JsEngine returns value [%s]" % jreturn)
diff --git a/module/plugins/crypter/NetfolderIn.py b/module/plugins/crypter/NetfolderIn.py
index 28ee3a9dd..62dc5c914 100644
--- a/module/plugins/crypter/NetfolderIn.py
+++ b/module/plugins/crypter/NetfolderIn.py
@@ -2,58 +2,56 @@
import re
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class NetfolderIn(SimpleCrypter):
- __name__ = "NetfolderIn"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?netfolder.in/((?P<id1>\w+)/\w+|folder.php\?folder_id=(?P<id2>\w+))'
- __version__ = "0.6"
+ __name__ = "NetfolderIn"
+ __type__ = "crypter"
+ __version__ = "0.72"
+
+ __pattern__ = r'http://(?:www\.)?netfolder\.in/(folder\.php\?folder_id=)?(?P<ID>\w+)(?(1)|/\w+)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
__description__ = """NetFolder.in decrypter plugin"""
- __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>'
- def decrypt(self, pyfile):
- # Request package
- self.html = self.load(pyfile.url)
+ NAME_PATTERN = r'<div class="Text">Inhalt des Ordners <span.*>(?P<N>.+)</span></div>'
- # Check for password protection
- if self.isPasswordProtected():
- self.html = self.submitPassword()
- if self.html is None:
- 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()
+ def prepare(self):
+ super(NetfolderIn, self).prepare()
- # Get package links
- package_links = self.getLinks()
+ # 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"))
- # Set package
- self.packages = [(package_name, package_links, folder_name)]
def isPasswordProtected(self):
-
if '<input type="password" name="password"' in self.html:
self.logDebug("Links are password protected")
return True
return False
+
def submitPassword(self):
# Gather data
try:
- m = re.match(self.__pattern__, self.pyfile.url)
- id = 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)
@@ -65,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 63e199a7a..1e280abd2 100644
--- a/module/plugins/crypter/NosvideoCom.py
+++ b/module/plugins/crypter/NosvideoCom.py
@@ -1,16 +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"
- __type__ = "crypter"
+ __name__ = "NosvideoCom"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
__pattern__ = r'http://(?:www\.)?nosvideo\.com/\?v=\w+'
- __version__ = "0.01"
+ __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+)"'
+ NAME_PATTERN = r'<[tT]itle>Watch (?P<N>.+?)<'
+
- LINK_PATTERN = r'href="(http://(?:w{3}\.)?nosupload.com/\?d=\w+)"'
- TITLE_PATTERN = r"<[tT]itle>Watch (?P<title>.+)</[tT]itle>"
+getInfo = create_getInfo(NosvideoCom)
diff --git a/module/plugins/crypter/OneKhDe.py b/module/plugins/crypter/OneKhDe.py
index 82fad86ce..cfb084da8 100644
--- a/module/plugins/crypter/OneKhDe.py
+++ b/module/plugins/crypter/OneKhDe.py
@@ -7,31 +7,35 @@ from module.plugins.Crypter import Crypter
class OneKhDe(Crypter):
- __name__ = "OneKhDe"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?1kh.de/f/'
- __version__ = "0.1"
+ __name__ = "OneKhDe"
+ __type__ = "crypter"
+ __version__ = "0.10"
+
+ __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)
- temp_links = []
+ 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))
- temp_links.append(new_link)
- self.links = temp_links
+ 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 f087370ac..9e06bdf32 100755
--- a/module/plugins/crypter/OronComFolder.py
+++ b/module/plugins/crypter/OronComFolder.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?oron.com/folder/\w+'
+ __name__ = "OronComFolder"
+ __type__ = "crypter"
__version__ = "0.11"
+
+ __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 e74f71a5c..b3d5a4bea 100644
--- a/module/plugins/crypter/PastebinCom.py
+++ b/module/plugins/crypter/PastebinCom.py
@@ -1,30 +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"
- __type__ = "crypter"
+ __name__ = "PastebinCom"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
__pattern__ = r'http://(?:www\.)?pastebin\.com/\w+'
- __version__ = "0.01"
+ __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 13d7671bf..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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?quickshare.cz/slozka-\d+.*'
- __version__ = "0.1"
+ __name__ = "QuickshareCzFolder"
+ __type__ = "crypter"
+ __version__ = "0.10"
+
+ __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)
- new_links = []
- found = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
- if found is None:
- self.fail("Parse error (FOLDER)")
- new_links.extend(re.findall(self.LINK_PATTERN, found.group(1)))
-
- if new_links:
- self.core.files.addLinks(new_links, pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ m = re.search(self.FOLDER_PATTERN, html, re.S)
+ if m is None:
+ self.error(_("FOLDER_PATTERN not found"))
+ self.urls.extend(re.findall(self.LINK_PATTERN, m.group(1)))
diff --git a/module/plugins/crypter/RSLayerCom.py b/module/plugins/crypter/RSLayerCom.py
index 9f1a9a394..cc3b23bbc 100644
--- a/module/plugins/crypter/RSLayerCom.py
+++ b/module/plugins/crypter/RSLayerCom.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?rs-layer.com/directory-'
+ __name__ = "RSLayerCom"
+ __type__ = "crypter"
__version__ = "0.21"
+
+ __pattern__ = r'http://(?:www\.)?rs-layer\.com/directory-'
+ __config__ = []
+
__description__ = """RS-Layer.com decrypter plugin"""
- __author_name__ = "hzpz"
- __author_mail__ = ""
+ __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 aad55c867..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,47 +12,57 @@ from module.plugins.Crypter import Crypter
class RelinkUs(Crypter):
- __name__ = "RelinkUs"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?relink.us/(f/|((view|go).php\?id=))(?P<id>.+)'
- __version__ = "3.0"
+ __name__ = "RelinkUs"
+ __type__ = "crypter"
+ __version__ = "3.11"
+
+ __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"
-
- # Constants
- PREFERRED_LINK_SOURCES = ['cnl2', 'dlc', 'web']
-
- OFFLINE_TOKEN = "<title>Tattooside"
- PASSWORD_TOKEN = "container_password.php"
- PASSWORD_ERROR_ROKEN = "You have entered an incorrect password"
- PASSWORD_SUBMIT_URL = "http://www.relink.us/container_password.php"
- CAPTCHA_TOKEN = "container_captcha.php"
- CAPTCHA_ERROR_ROKEN = "You have solved the captcha wrong"
- CAPTCHA_IMG_URL = "http://www.relink.us/core/captcha/circlecaptcha.php"
- CAPTCHA_SUBMIT_URL = "http://www.relink.us/container_captcha.php"
- FILE_TITLE_REGEX = r"<th>Title</th><td><i>(.*)</i></td></tr>"
- FILE_NOTITLE = 'No title'
+ __license__ = "GPLv3"
+ __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"),
+ ("AndroKev", "neureither.kevin@gmail.com")]
+
+
+ PREFERRED_LINK_SOURCES = ["cnl2", "dlc", "web"]
+
+ OFFLINE_TOKEN = r'<title>Tattooside'
+
+ PASSWORD_TOKEN = r'container_password.php'
+ PASSWORD_ERROR_ROKEN = r'You have entered an incorrect password'
+ PASSWORD_SUBMIT_URL = r'http://www.relink.us/container_password.php'
+
+ CAPTCHA_TOKEN = r'container_captcha.php'
+ CAPTCHA_ERROR_ROKEN = r'You have solved the captcha wrong'
+ CAPTCHA_IMG_URL = r'http://www.relink.us/core/captcha/circlecaptcha.php'
+ CAPTCHA_SUBMIT_URL = r'http://www.relink.us/container_captcha.php'
+
+ FILE_TITLE_REGEX = r'<th>Title</th><td>(.*)</td></tr>'
+ FILE_NOTITLE = r'No title'
CNL2_FORM_REGEX = r'<form id="cnl_form-(.*?)</form>'
CNL2_FORMINPUT_REGEX = r'<input.*?name="%s".*?value="(.*?)"'
CNL2_JK_KEY = "jk"
CNL2_CRYPTED_KEY = "crypted"
+
DLC_LINK_REGEX = r'<a href=".*?" class="dlc_button" target="_blank">'
- DLC_DOWNLOAD_URL = "http://www.relink.us/download.php"
- WEB_FORWARD_REGEX = r"getFile\('(?P<link>.+)'\)"
- WEB_FORWARD_URL = "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):
+ def decrypt(self, pyfile):
# Init
self.initPackage(pyfile)
@@ -61,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()
@@ -85,17 +97,17 @@ 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()
- self.url = pyfile.url
+
def requestPackage(self):
- self.html = self.load(self.url, decode=True)
+ self.html = self.load(self.pyfile.url, decode=True)
+
def isOnline(self):
if self.OFFLINE_TOKEN in self.html:
@@ -103,23 +115,27 @@ class RelinkUs(Crypter):
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
@@ -129,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()
@@ -146,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()
@@ -171,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:
@@ -187,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:
@@ -197,49 +217,58 @@ class RelinkUs(Crypter):
try:
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()
+ dlc_filepath = os.path.join(self.config['general']['download_folder'], dlc_filename)
+ 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):
+ 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):
+ def _getLinks(self, crypted, jk):
# Get key
jreturn = self.js.eval("%s f()" % jk)
self.logDebug("JsEngine returns value [%s]" % jreturn)
diff --git a/module/plugins/crypter/SafelinkingNet.py b/module/plugins/crypter/SafelinkingNet.py
index 4a907c28d..709083b51 100644
--- a/module/plugins/crypter/SafelinkingNet.py
+++ b/module/plugins/crypter/SafelinkingNet.py
@@ -1,64 +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'
- __type__ = 'crypter'
- __pattern__ = r'https?://(?:www\.)?safelinking.net/([pd])/\w+'
- __version__ = '0.1'
+ __name__ = "SafelinkingNet"
+ __type__ = "crypter"
+ __version__ = "0.11"
+
+ __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.core.files.addLinks([m.group(1)], pyfile.package().id)
+
+ 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 = ""
- packageLinks = []
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):
- m = re.search(self.__Solvemedia_pattern__, self.html)
+ 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_challenge'] = challenge
+ 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
@@ -72,9 +75,7 @@ class SafelinkingNet(Crypter):
if m:
linkDict = json_loads(m.group(1))
for link in linkDict:
- if not "http://" in link["full"]:
- packageLinks.append("https://safelinking.net/d/" + link["full"])
+ if not "http://" in link['full']:
+ self.urls.append("https://safelinking.net/d/" + link['full'])
else:
- packageLinks.append(link["full"])
-
- self.core.files.addLinks(packageLinks, pyfile.package().id)
+ self.urls.append(link['full'])
diff --git a/module/plugins/crypter/SecuredIn.py b/module/plugins/crypter/SecuredIn.py
index 771205ec8..cbfa919ac 100644
--- a/module/plugins/crypter/SecuredIn.py
+++ b/module/plugins/crypter/SecuredIn.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?secured\.in/download-[\d]+-[\w]{8}\.html'
+ __name__ = "SecuredIn"
+ __type__ = "crypter"
__version__ = "0.21"
+
+ __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 6fbbfedb3..000000000
--- a/module/plugins/crypter/SerienjunkiesOrg.py
+++ /dev/null
@@ -1,318 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-from time import sleep
-import random
-from module.plugins.Crypter import Crypter
-from module.lib.BeautifulSoup import BeautifulSoup
-from module.unescape import unescape
-
-
-class SerienjunkiesOrg(Crypter):
- __name__ = "SerienjunkiesOrg"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?(serienjunkies.org|dokujunkies.org)/.*?'
- __version__ = "0.39"
- __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 816842216..d2e8138f6 100644
--- a/module/plugins/crypter/ShareLinksBiz.py
+++ b/module/plugins/crypter/ShareLinksBiz.py
@@ -9,23 +9,27 @@ from module.plugins.Crypter import Crypter
class ShareLinksBiz(Crypter):
- __name__ = "ShareLinksBiz"
- __type__ = "crypter"
- __pattern__ = r'(?P<base>http://(?:www\.)?(share-links|s2l)\.biz)/(?P<id>_?[0-9a-z]+)(/.*)?'
- __version__ = "1.13"
+ __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):
+ def decrypt(self, pyfile):
# Init
self.initFile(pyfile)
@@ -59,37 +63,43 @@ class ShareLinksBiz(Crypter):
# Pack
self.packages = [(package_name, package_links, package_folder)]
+
def initFile(self, pyfile):
url = pyfile.url
if 's2l.biz' in url:
url = self.load(url, just_header=True)['location']
- self.baseUrl = re.match(self.__pattern__, url).group(1)
- self.fileId = re.match(self.__pattern__, url).group('id')
+ self.baseUrl = "http://www.%s.biz" % re.match(self.__pattern__, url).group(1)
+ 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)
@@ -97,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()
@@ -112,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):
@@ -128,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:
@@ -171,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:
@@ -210,6 +226,7 @@ class ShareLinksBiz(Crypter):
package_links.append(link)
return package_links
+
def handleCNL2(self):
package_links = []
self.logDebug("Handling CNL2 links")
@@ -219,16 +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):
+ 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]))
@@ -243,8 +260,8 @@ class ShareLinksBiz(Crypter):
# Log and return
return crypted, jk
- def _getLinks(self, crypted, jk):
+ def _getLinks(self, crypted, jk):
# Get key
jreturn = self.js.eval("%s f()" % jk)
self.logDebug("JsEngine returns value [%s]" % jreturn)
diff --git a/module/plugins/crypter/ShareRapidComFolder.py b/module/plugins/crypter/ShareRapidComFolder.py
deleted file mode 100644
index 15c8dccde..000000000
--- a/module/plugins/crypter/ShareRapidComFolder.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
-
-
-class ShareRapidComFolder(SimpleCrypter):
- __name__ = "ShareRapidComFolder"
- __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/.+)'
- __version__ = "0.01"
- __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 4bb1562ee..ddde7dec2 100644
--- a/module/plugins/crypter/SpeedLoadOrgFolder.py
+++ b/module/plugins/crypter/SpeedLoadOrgFolder.py
@@ -1,27 +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"
- __type__ = "crypter"
+ __name__ = "SpeedLoadOrgFolder"
+ __type__ = "crypter"
+ __version__ = "0.30"
+
__pattern__ = r'http://(?:www\.)?speedload\.org/(\d+~f$|folder/\d+/)'
- __version__ = "0.3"
+ __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 e97a741e0..5173421f1 100644
--- a/module/plugins/crypter/StealthTo.py
+++ b/module/plugins/crypter/StealthTo.py
@@ -1,48 +1,19 @@
# -*- coding: utf-8 -*-
-import re
+from module.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo
-from module.plugins.Crypter import Crypter
+class StealthTo(DeadCrypter):
+ __name__ = "StealthTo"
+ __type__ = "crypter"
+ __version__ = "0.20"
-class StealthTo(Crypter):
- __name__ = "StealthTo"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?stealth.to/folder/'
- __version__ = "0.1"
- __description__ = """Stealth.to decrypter plugin"""
- __author_name__ = "spoob"
- __author_mail__ = "spoob@pyload.org"
-
- def __init__(self, parent):
- Crypter.__init__(self, parent)
- self.parent = parent
- self.html = None
+ __pattern__ = r'http://(?:www\.)?stealth\.to/folder/.+'
+ __config__ = []
- 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, cookies=True)
- temp_links = []
- ids = []
- ats = [] # authenticity_token
- inputs = re.findall(r"(<(input|form)[^>]+)", self.html)
- for input in inputs:
- if re.search(r"name=\"authenticity_token\"", input[0]):
- ats.append(re.search(r"value=\"([^\"]+)", input[0]).group(1))
- if re.search(r"name=\"id\"", input[0]):
- ids.append(re.search(r"value=\"([^\"]+)", input[0]).group(1))
+ __description__ = """Stealth.to decrypter plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org")]
- for i in xrange(0, len(ids)):
- self.req.load(url + "/web",
- post={"authenticity_token": ats[i], "id": str(ids[i]), "link": ("download_" + str(ids[i]))},
- cookies=True)
- new_html = self.req.load(url + "/web", post={"authenticity_token": ats[i], "id": str(ids[i]), "link": "1"},
- cookies=True)
- temp_links.append(re.search(r"iframe src=\"(.*)\" frameborder", new_html).group(1))
- self.links = temp_links
+getInfo = create_getInfo(StealthTo)
diff --git a/module/plugins/crypter/TnyCz.py b/module/plugins/crypter/TnyCz.py
index 6c56f7639..d36128550 100644
--- a/module/plugins/crypter/TnyCz.py
+++ b/module/plugins/crypter/TnyCz.py
@@ -1,38 +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/>.
-
- @author: Walter Purcaro
-"""
-
-from module.plugins.internal.SimpleCrypter import SimpleCrypter
+from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
import re
class TnyCz(SimpleCrypter):
- __name__ = "TnyCz"
- __type__ = "crypter"
+ __name__ = "TnyCz"
+ __type__ = "crypter"
+ __version__ = "0.03"
+
__pattern__ = r'http://(?:www\.)?tny\.cz/\w+'
- __version__ = "0.01"
+ __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")]
+
+
+ NAME_PATTERN = r'<title>(?P<N>.+) - .+</title>'
- TITLE_PATTERN = r'<title>(?P<title>.+) - .+</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 84a476a38..10780dd45 100644
--- a/module/plugins/crypter/TrailerzoneInfo.py
+++ b/module/plugins/crypter/TrailerzoneInfo.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?trailerzone.info/.*?'
+ __name__ = "TrailerzoneInfo"
+ __type__ = "crypter"
__version__ = "0.03"
+
+ __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 d9e63b4ce..c6734c997 100644
--- a/module/plugins/crypter/TurbobitNetFolder.py
+++ b/module/plugins/crypter/TurbobitNetFolder.py
@@ -1,50 +1,47 @@
# -*- 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"
- __type__ = "crypter"
+ __name__ = "TurbobitNetFolder"
+ __type__ = "crypter"
+ __version__ = "0.05"
+
__pattern__ = r'http://(?:www\.)?turbobit\.net/download/folder/(?P<ID>\w+)'
- __version__ = "0.03"
+ __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")]
+
+
+ NAME_PATTERN = r'src=\'/js/lib/grid/icon/folder.png\'> <span>(?P<N>.+?)</span>'
- TITLE_PATTERN = r"src='/js/lib/grid/icon/folder.png'> <span>(?P<title>.+?)</span>"
def _getLinks(self, id, page=1):
gridFile = self.load("http://turbobit.net/downloadfolder/gridFile",
get={"rootId": id, "rows": 200, "page": page}, decode=True)
grid = json_loads(gridFile)
- if grid["rows"]:
- for i in grid["rows"]:
- yield i["id"]
+ if grid['rows']:
+ for i in grid['rows']:
+ yield i['id']
for id in self._getLinks(id, page + 1):
yield id
else:
return
+
def getLinks(self):
- id = re.match(self.__pattern__, self.pyfile.url).group("ID")
+ 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 0bc770f99..0db3470cc 100644
--- a/module/plugins/crypter/TusfilesNetFolder.py
+++ b/module/plugins/crypter/TusfilesNetFolder.py
@@ -1,46 +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/>.
-#
-# @author: Walter Purcaro
-###############################################################################
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"
- __type__ = "crypter"
- __pattern__ = r'https?://(?:www\.)?tusfiles\.net/go/(?P<ID>\w+)/?'
- __version__ = "0.01"
+class TusfilesNetFolder(XFSCrypter):
+ __name__ = "TusfilesNetFolder"
+ __type__ = "crypter"
+ __version__ = "0.07"
+
+ __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")]
+
+
+ HOSTER_DOMAIN = "tusfiles.net"
- LINK_PATTERN = r'<TD align=left><a href="(.*?)">'
- TITLE_PATTERN = r'<Title>.*?\: (?P<title>.+) folder</Title>'
- PAGES_PATTERN = r'>\((?P<pages>\d+) \w+\)<'
+ PAGES_PATTERN = r'>\((\d+) \w+\)<'
+
+ URL_REPLACEMENTS = [(__pattern__ + ".*", r'https://www.tusfiles.net/go/\g<ID>/')]
- FILE_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:
@@ -50,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 eebb14497..a1f3ed5ea 100644
--- a/module/plugins/crypter/UlozToFolder.py
+++ b/module/plugins/crypter/UlozToFolder.py
@@ -5,38 +5,42 @@ from module.plugins.Crypter import Crypter
class UlozToFolder(Crypter):
- __name__ = "UlozToFolder"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj.cz|zachowajto.pl)/(m|soubory)/.*'
- __version__ = "0.2"
+ __name__ = "UlozToFolder"
+ __type__ = "crypter"
+ __version__ = "0.20"
+
+ __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>'
NEXT_PAGE_PATTERN = r'<a class="next " href="/([^"]+)">&nbsp;</a>'
+
def decrypt(self, pyfile):
html = self.load(pyfile.url)
new_links = []
for i in xrange(1, 100):
- self.logInfo("Fetching links from page %i" % i)
- found = re.search(self.FOLDER_PATTERN, html, re.DOTALL)
- if found is None:
- self.fail("Parse error (FOLDER)")
-
- new_links.extend(re.findall(self.LINK_PATTERN, found.group(1)))
- found = re.search(self.NEXT_PAGE_PATTERN, html)
- if found:
- html = self.load("http://ulozto.net/" + found.group(1))
+ self.logInfo(_("Fetching links from page %i") % i)
+ m = re.search(self.FOLDER_PATTERN, html, re.S)
+ if m is None:
+ 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)
+ if m:
+ html = self.load("http://ulozto.net/" + m.group(1))
else:
break
else:
- self.logInfo("Limit of 99 pages reached, aborting")
+ self.logInfo(_("Limit of 99 pages reached, aborting"))
if new_links:
- self.core.files.addLinks(map(lambda s: "http://ulozto.net/%s" % s, new_links), pyfile.package().id)
- else:
- self.fail('Could not extract any links')
+ self.urls = [map(lambda s: "http://ulozto.net/%s" % s, new_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 97c77fdce..0a71add70 100644
--- a/module/plugins/crypter/UploadedToFolder.py
+++ b/module/plugins/crypter/UploadedToFolder.py
@@ -1,49 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|folder|list)/(?P<id>\w+)'
- __version__ = "0.3"
+ __name__ = "UploadedToFolder"
+ __type__ = "crypter"
+ __version__ = "0.42"
+
+ __pattern__ = r'http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|folder|list)/(?P<ID>\w+)'
+ __config__ = [("use_subfolder", "bool", "Save package to subfolder", True),
+ ("subfolder_per_package", "bool", "Create a subfolder for each package", True)]
+
__description__ = """UploadedTo decrypter plugin"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
- PLAIN_PATTERN = r'<small class="date"><a href="(?P<plain>[\w/]+)" onclick='
- TITLE_PATTERN = r'<title>(?P<title>[^<]+)</title>'
- 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 0b983c705..c3c5b8222 100644
--- a/module/plugins/crypter/WiiReloadedOrg.py
+++ b/module/plugins/crypter/WiiReloadedOrg.py
@@ -1,13 +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"
- __type__ = "crypter"
- __pattern__ = r'http://(?:www\.)?wii-reloaded\.org/protect/get\.php\?i=.+'
+ __name__ = "WiiReloadedOrg"
+ __type__ = "crypter"
__version__ = "0.11"
+
+ __pattern__ = r'http://(?:www\.)?wii-reloaded\.org/protect/get\.php\?i=.+'
+ __config__ = []
+
__description__ = """Wii-Reloaded.org decrypter plugin"""
- __author_name__ = "hzpz"
- __author_mail__ = ""
+ __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 c04fc69f8..f2ecbee5a 100644
--- a/module/plugins/crypter/XupPl.py
+++ b/module/plugins/crypter/XupPl.py
@@ -4,17 +4,22 @@ from module.plugins.Crypter import Crypter
class XupPl(Crypter):
- __name__ = "XupPl"
- __type__ = "crypter"
- __pattern__ = r'https?://(?:[^/]*\.)?xup\.pl/.*'
- __version__ = "0.1"
+ __name__ = "XupPl"
+ __type__ = "crypter"
+ __version__ = "0.10"
+
+ __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):
header = self.load(pyfile.url, just_header=True)
if 'location' in header:
- self.core.files.addLinks([header['location']], pyfile.package().id)
+ 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 e6976471c..73ebf5fb3 100644
--- a/module/plugins/crypter/YoutubeBatch.py
+++ b/module/plugins/crypter/YoutubeBatch.py
@@ -1,67 +1,60 @@
# -*- 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/>.
-
- @author: Walter Purcaro
-"""
+import re
from urlparse import urljoin
-import re
from module.common.json_layer import json_loads
from module.plugins.Crypter import Crypter
from module.utils import save_join
-API_KEY = "AIzaSyCKnWLNlkX-L4oD1aEzqqhRw1zczeD6_k0"
-
class YoutubeBatch(Crypter):
- __name__ = "YoutubeBatch"
- __type__ = "crypter"
- __pattern__ = r'https?://(?:www\.)?(m\.)?youtube\.com/(?P<TYPE>user|playlist|view_play_list)(/|.*?[?&](?:list|p)=)(?P<ID>[\w-]+)'
- __version__ = "1.00"
- __description__ = """Youtube.com channel & playlist decrypter plugin"""
- __config__ = [("likes", "bool", "Grab user (channel) liked videos", False),
+ __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__ = [("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)]
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+
+ __description__ = """Youtube.com channel & playlist decrypter plugin"""
+ __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"]:
- channel = channels["items"][0]
- return {"id": channel["id"],
- "title": channel["snippet"]["title"],
- "relatedPlaylists": channel["contentDetails"]["relatedPlaylists"],
+ if channels['items']:
+ channel = channels['items'][0]
+ return {"id": channel['id'],
+ "title": channel['snippet']['title'],
+ "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"]:
- playlist = playlists["items"][0]
+ if playlists['items']:
+ playlist = playlists['items'][0]
return {"id": p_id,
- "title": playlist["snippet"]["title"],
- "channelId": playlist["snippet"]["channelId"],
- "channelTitle": playlist["snippet"]["channelTitle"]}
+ "title": playlist['snippet']['title'],
+ "channelId": playlist['snippet']['channelId'],
+ "channelTitle": playlist['snippet']['channelTitle']}
+
def _getPlaylists(self, id, token=None):
req = {"part": "id", "maxResults": "50", "channelId": id}
@@ -70,16 +63,18 @@ class YoutubeBatch(Crypter):
playlists = self.api_response("playlists", req)
- for playlist in playlists["items"]:
- yield playlist["id"]
+ for playlist in playlists['items']:
+ yield playlist['id']
if "nextPageToken" in playlists:
- for item in self._getPlaylists(id, playlists["nextPageToken"]):
+ 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:
@@ -87,20 +82,22 @@ class YoutubeBatch(Crypter):
playlist = self.api_response("playlistItems", req)
- for item in playlist["items"]:
- yield item["contentDetails"]["videoId"]
+ for item in playlist['items']:
+ yield item['contentDetails']['videoId']
if "nextPageToken" in playlist:
- for item in self._getVideosId(id, playlist["nextPageToken"]):
+ 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):
- match = re.match(self.__pattern__, pyfile.url)
- m_id = match.group("ID")
- m_type = match.group("TYPE")
+ m = re.match(self.__pattern__, pyfile.url)
+ m_id = m.group('ID')
+ m_type = m.group('TYPE')
if m_type == "user":
self.logDebug("Url recognized as Channel")
@@ -108,18 +105,18 @@ class YoutubeBatch(Crypter):
channel = self.getChannel(user)
if channel:
- playlists = self.getPlaylists(channel["id"])
- self.logDebug("%s playlist\s found on channel \"%s\"" % (len(playlists), channel["title"]))
+ playlists = self.getPlaylists(channel['id'])
+ self.logDebug("%s playlist\s found on channel \"%s\"" % (len(playlists), channel['title']))
- relatedplaylist = {p_name: self.getPlaylist(p_id) for p_name, p_id in channel["relatedPlaylists"].iteritems()}
+ relatedplaylist = {p_name: self.getPlaylist(p_id) for p_name, p_id in channel['relatedPlaylists'].iteritems()}
self.logDebug("Channel's related playlists found = %s" % relatedplaylist.keys())
- relatedplaylist["uploads"]["title"] = "Unplaylisted videos"
- relatedplaylist["uploads"]["checkDups"] = True #: checkDups flag
+ relatedplaylist['uploads']['title'] = "Unplaylisted videos"
+ relatedplaylist['uploads']['checkDups'] = True #: checkDups flag
for p_name, p_data in relatedplaylist.iteritems():
if self.getConfig(p_name):
- p_data["title"] += " of " + user
+ p_data['title'] += " of " + user
playlists.append(p_data)
else:
playlists = []
@@ -128,14 +125,14 @@ 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
for p in playlists:
- p_name = p["title"]
- p_videos = self.getVideosId(p["id"])
- p_folder = save_join(self.config['general']['download_folder'], p["channelTitle"], p_name)
+ p_name = p['title']
+ p_videos = self.getVideosId(p['id'])
+ p_folder = save_join(self.config['general']['download_folder'], p['channelTitle'], p_name)
self.logDebug("%s video\s found on playlist \"%s\"" % (len(p_videos), p_name))
if not p_videos:
diff --git a/module/plugins/hooks/AlldebridCom.py b/module/plugins/hooks/AlldebridCom.py
index 0f8d3bfbb..d5986053f 100644
--- a/module/plugins/hooks/AlldebridCom.py
+++ b/module/plugins/hooks/AlldebridCom.py
@@ -1,29 +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 70e60f56c..a32de7f42 100644
--- a/module/plugins/hooks/BypassCaptcha.py
+++ b/module/plugins/hooks/BypassCaptcha.py
@@ -1,70 +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/>.
-
- @author: RaNaN, Godofdream, zoidberg
-"""
-
-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"
- __description__ = """Send captchas to BypassCaptcha.com"""
- __config__ = [("activated", "bool", "Activated", False),
- ("force", "bool", "Force BC even if client is connected", False),
+ __name__ = "BypassCaptcha"
+ __type__ = "hook"
+ __version__ = "0.05"
+
+ __config__ = [("force", "bool", "Force BC even if client is connected", False),
("passkey", "password", "Passkey", "")]
- __author_name__ = ("RaNaN", "Godofdream", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "soilfcition@gmail.com", "zoidberg@mujmail.cz")
+
+ __description__ = """Send captchas to BypassCaptcha.com"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("Godofdream", "soilfcition@gmail.com"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ PYLOAD_KEY = "4f771155b640970d5607f919a615bdefc67e7d32"
SUBMIT_URL = "http://bypasscaptcha.com/upload.php"
RESPOND_URL = "http://bypasscaptcha.com/check_value.php"
GETCREDITS_URL = "http://bypasscaptcha.com/ex_left.php"
+
+ #@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()
@@ -72,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:
@@ -118,15 +119,18 @@ 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)
+ 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)
+ self.respond(task.data['ticket'], False)
+
def processCaptcha(self, task):
c = task.captchaFile
@@ -136,5 +140,5 @@ class BypassCaptcha(Hook):
task.error = e.getCode()
return
- task.data["ticket"] = ticket
+ task.data['ticket'] = ticket
task.setResult(result)
diff --git a/module/plugins/hooks/Captcha9kw.py b/module/plugins/hooks/Captcha9kw.py
index c86f92972..33ad00c49 100755
--- a/module/plugins/hooks/Captcha9kw.py
+++ b/module/plugins/hooks/Captcha9kw.py
@@ -1,168 +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/>.
-
- @author: mkaay, RaNaN, zoidberg
-"""
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"
+ __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"""
- __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", "")]
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
-
- API_URL = "://www.9kw.eu/index.cgi"
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ 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 23d71ff5f..b6e38d8bb 100644
--- a/module/plugins/hooks/CaptchaBrotherhood.py
+++ b/module/plugins/hooks/CaptchaBrotherhood.py
@@ -1,76 +1,80 @@
# -*- 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/>.
-
- @author: mkaay, RaNaN, zoidberg
-"""
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
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"
- __description__ = """Send captchas to CaptchaBrotherhood.com"""
- __config__ = [("activated", "bool", "Activated", False),
- ("username", "str", "Username", ""),
+ __name__ = "CaptchaBrotherhood"
+ __type__ = "hook"
+ __version__ = "0.06"
+
+ __config__ = [("username", "str", "Username", ""),
("force", "bool", "Force CT even if client is connected", False),
("passkey", "password", "Password", "")]
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+
+ __description__ = """Send captchas to CaptchaBrotherhood.com"""
+ __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
+ self.info['credits'] = credits
return credits
+
def submit(self, captcha, captchaType="file", match=None):
try:
img = Image.open(captcha)
@@ -102,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:
@@ -150,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
@@ -164,5 +172,5 @@ class CaptchaBrotherhood(Hook):
task.error = e.getCode()
return
- task.data["ticket"] = ticket
+ task.data['ticket'] = ticket
task.setResult(result)
diff --git a/module/plugins/hooks/CaptchaTrader.py b/module/plugins/hooks/CaptchaTrader.py
deleted file mode 100644
index 051dc6c2b..000000000
--- a/module/plugins/hooks/CaptchaTrader.py
+++ /dev/null
@@ -1,157 +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/>.
-
- @author: mkaay, RaNaN
-"""
-
-from thread import start_new_thread
-from pycurl import FORM_FILE, LOW_SPEED_TIME
-
-from module.common.json_layer import json_loads
-from module.network.RequestFactory import getURL, getRequest
-from module.network.HTTPRequest import BadHeader
-from module.plugins.Hook import Hook
-
-PYLOAD_KEY = "9f65e7f381c3af2b076ea680ae96b0b7"
-
-
-class CaptchaTraderException(Exception):
- def __init__(self, err):
- self.err = err
-
- def getCode(self):
- return self.err
-
- def __str__(self):
- return "<CaptchaTraderException %s>" % self.err
-
- def __repr__(self):
- return "<CaptchaTraderException %s>" % self.err
-
-
-class CaptchaTrader(Hook):
- __name__ = "CaptchaTrader"
- __version__ = "0.16"
- __description__ = """Send captchas to captchatrader.com"""
- __config__ = [("activated", "bool", "Activated", False),
- ("username", "str", "Username", ""),
- ("force", "bool", "Force CT even if client is connected", False),
- ("passkey", "password", "Password", "")]
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
-
- SUBMIT_URL = "http://api.captchatrader.com/submit"
- RESPOND_URL = "http://api.captchatrader.com/respond"
- GETCREDITS_URL = "http://api.captchatrader.com/get_credits/username:%(user)s/password:%(password)s/"
-
- def setup(self):
- self.info = {}
-
- def getCredits(self):
- json = getURL(CaptchaTrader.GETCREDITS_URL % {"user": self.getConfig("username"),
- "password": self.getConfig("passkey")})
- response = json_loads(json)
- if response[0] < 0:
- raise CaptchaTraderException(response[1])
- else:
- self.logInfo(_("%s credits left") % response[1])
- self.info["credits"] = response[1]
- return response[1]
-
- def submit(self, captcha, captchaType="file", match=None):
- if not PYLOAD_KEY:
- raise CaptchaTraderException("No API Key Specified!")
-
- #if type(captcha) == str and captchaType == "file":
- # raise CaptchaTraderException("Invalid Type")
- assert captchaType in ("file", "url-jpg", "url-jpeg", "url-png", "url-bmp")
-
- req = getRequest()
-
- #raise timeout threshold
- req.c.setopt(LOW_SPEED_TIME, 80)
-
- try:
- json = req.load(CaptchaTrader.SUBMIT_URL, post={"api_key": PYLOAD_KEY,
- "username": self.getConfig("username"),
- "password": self.getConfig("passkey"),
- "value": (FORM_FILE, captcha),
- "type": captchaType}, multipart=True)
- finally:
- req.close()
-
- response = json_loads(json)
- if response[0] < 0:
- raise CaptchaTraderException(response[1])
-
- ticket = response[0]
- result = response[1]
- self.logDebug("result %s : %s" % (ticket, result))
-
- return ticket, result
-
- def respond(self, ticket, success):
- try:
- json = getURL(CaptchaTrader.RESPOND_URL, post={"is_correct": 1 if success else 0,
- "username": self.getConfig("username"),
- "password": self.getConfig("passkey"),
- "ticket": ticket})
-
- response = json_loads(json)
- if response[0] < 0:
- raise CaptchaTraderException(response[1])
-
- except BadHeader, e:
- self.logError(_("Could not send response."), str(e))
-
- def newCaptchaTask(self, task):
- if not task.isTextual():
- return False
-
- if not self.getConfig("username") or not self.getConfig("passkey"):
- return False
-
- if self.core.isClientConnected() and not self.getConfig("force"):
- return False
-
- if self.getCredits() > 10:
- task.handler.append(self)
- task.setWaiting(100)
- start_new_thread(self.processCaptcha, (task,))
-
- else:
- self.logInfo(_("Your CaptchaTrader Account has not enough credits"))
-
- def captchaCorrect(self, task):
- if "ticket" in task.data:
- ticket = task.data["ticket"]
- self.respond(ticket, True)
-
- def captchaInvalid(self, task):
- if "ticket" in task.data:
- ticket = task.data["ticket"]
- self.respond(ticket, False)
-
- def processCaptcha(self, task):
- c = task.captchaFile
- try:
- ticket, result = self.submit(c)
- except CaptchaTraderException, e:
- task.error = e.getCode()
- return
-
- task.data["ticket"] = ticket
- task.setResult(result)
diff --git a/module/plugins/hooks/Checksum.py b/module/plugins/hooks/Checksum.py
index af37d69e6..8d9f8f981 100644
--- a/module/plugins/hooks/Checksum.py
+++ b/module/plugins/hooks/Checksum.py
@@ -1,31 +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/>.
-
- @author: zoidberg
-"""
-
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):
@@ -33,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()
@@ -43,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
@@ -53,32 +38,46 @@ def computeChecksum(local_file, algorithm):
class Checksum(Hook):
- __name__ = "Checksum"
- __version__ = "0.12"
- __description__ = """Verify downloaded file size and checksum"""
- __config__ = [("activated", "bool", "Activated", False),
+ __name__ = "Checksum"
+ __type__ = "hook"
+ __version__ = "0.15"
+
+ __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)]
- __author_name__ = ("zoidberg", "Walter Purcaro")
- __author_mail__ = ("zoidberg@mujmail.cz", "vuolter@gmail.com")
+
+ __description__ = """Verify downloaded file size and checksum"""
+ __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(
getattr(hashlib, "algorithms", ("md5", "sha1", "sha224", "sha256", "sha384", "sha512")), reverse=True)
self.algorithms.extend(["crc32", "adler32"])
- self.formats = self.algorithms + ['sfv', 'crc', 'hash']
+ self.formats = self.algorithms + ["sfv", "crc", "hash"]
+
def downloadFinished(self, pyfile):
"""
@@ -87,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
@@ -111,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']
@@ -125,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")
@@ -145,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)
+ file_type = splitext(link['name'])[1][1:].lower()
if file_type not in self.formats:
continue
- hash_file = fs_encode(save_join(download_folder, link["name"]))
+ 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:
@@ -172,14 +177,14 @@ class Checksum(Hook):
for m in re.finditer(self.regexps.get(file_type, self.regexps['default']), text):
data = m.groupdict()
- self.logDebug(link["name"], data)
+ 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 002fd4cd7..04aac2f10 100644
--- a/module/plugins/hooks/ClickAndLoad.py
+++ b/module/plugins/hooks/ClickAndLoad.py
@@ -1,52 +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/>.
-
- @author: RaNaN
- @interface-version: 0.2
-"""
-
import socket
import thread
from module.plugins.Hook import Hook
-class ClickAndLoad(Hook):
- __name__ = "ClickAndLoad"
- __version__ = "0.22"
- __description__ = """Gives abillity to use jd's click and load. depends on webinterface"""
- __config__ = [("activated", "bool", "Activated", True),
- ("extern", "bool", "Allow external link adding", False)]
- __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()
@@ -88,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 f7bc1b90f..f03ac4567 100644
--- a/module/plugins/hooks/DeathByCaptcha.py
+++ b/module/plugins/hooks/DeathByCaptcha.py
@@ -1,33 +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/>.
-
- @author: mkaay, RaNaN, zoidberg
-"""
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):
@@ -40,40 +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"
- __description__ = """Send captchas to DeathByCaptcha.com"""
- __config__ = [("activated", "bool", "Activated", False),
- ("username", "str", "Username", ""),
+ __name__ = "DeathByCaptcha"
+ __type__ = "hook"
+ __version__ = "0.04"
+
+ __config__ = [("username", "str", "Username", ""),
("passkey", "password", "Password", ""),
("force", "bool", "Force DBC even if client is connected", False)]
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+
+ __description__ = """Send captchas to DeathByCaptcha.com"""
+ __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()
@@ -85,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:
@@ -113,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:
@@ -142,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
@@ -181,9 +186,10 @@ class DeathByCaptcha(Hook):
self.logError(e.getDesc())
return False
- balance, rate = self.info["balance"], self.info["rate"]
- self.logInfo("Account balance: US$%.3f (%d captchas left at %.2f cents each)" % (balance / 100,
- balance // rate, rate))
+ balance, rate = self.info['balance'], self.info['rate']
+ self.logInfo(_("Account balance"),
+ _("US$%.3f (%d captchas left at %.2f cents each)") % (balance / 100,
+ balance // rate, rate))
if balance > rate:
task.handler.append(self)
@@ -191,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:
@@ -209,5 +219,5 @@ class DeathByCaptcha(Hook):
self.logError(e.getDesc())
return
- task.data["ticket"] = ticket
+ task.data['ticket'] = ticket
task.setResult(result)
diff --git a/module/plugins/hooks/DebridItaliaCom.py b/module/plugins/hooks/DebridItaliaCom.py
index fb6be674f..e31bc98d7 100644
--- a/module/plugins/hooks/DebridItaliaCom.py
+++ b/module/plugins/hooks/DebridItaliaCom.py
@@ -1,41 +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 3bc98a7b3..5d2b78d50 100644
--- a/module/plugins/hooks/DeleteFinished.py
+++ b/module/plugins/hooks/DeleteFinished.py
@@ -1,84 +1,79 @@
# -*- 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.database import style
+from module.plugins.Hook import Hook
- 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 DeleteFinished(Hook):
+ __name__ = "DeleteFinished"
+ __type__ = "hook"
+ __version__ = "1.11"
- @author: Walter Purcaro
-"""
+ __config__ = [('activated', 'bool', 'Activated', 'False'),
+ ('interval', 'int', 'Delete every (hours)', '72'),
+ ('deloffline', 'bool', 'Delete packages with offline links', 'False')]
-from module.database import style
-from module.plugins.Hook import Hook
+ __description__ = """Automatically delete all finished packages from queue"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
-class DeleteFinished(Hook):
- __name__ = 'DeleteFinished'
- __version__ = '1.09'
- __description__ = 'Automatically delete all finished packages from queue'
- __config__ = [
- ('activated', 'bool', 'Activated', 'False'),
- ('interval', 'int', 'Delete every (hours)', '72'),
- ('deloffline', 'bool', 'Delete packages with offline links', 'False')
- ]
- __author_name__ = ('Walter Purcaro')
- __author_mail__ = ('vuolter@gmail.com')
+ # event_list = ["pluginConfigChanged"]
+
## overwritten methods ##
def periodical(self):
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 41a20e5d1..4996e212d 100644
--- a/module/plugins/hooks/DownloadScheduler.py
+++ b/module/plugins/hooks/DownloadScheduler.py
@@ -1,44 +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/>.
-
- @author: zoidberg
- 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"
- __description__ = """Download Scheduler"""
- __config__ = [("activated", "bool", "Activated", False),
- ("timetable", "str", "List time periods as hh:mm full or number(kB/s)",
+ __name__ = "DownloadScheduler"
+ __type__ = "hook"
+ __version__ = "0.22"
+
+ __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)]
- __author_name__ = ("zoidberg", "stickell")
- __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+
+ __description__ = """Download Scheduler"""
+ __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")
@@ -46,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()
@@ -66,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()
@@ -77,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 a3a2dcb92..0dab2a7fe 100644
--- a/module/plugins/hooks/EasybytezCom.py
+++ b/module/plugins/hooks/EasybytezCom.py
@@ -2,33 +2,38 @@
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"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+class EasybytezCom(MultiHook):
+ __name__ = "EasybytezCom"
+ __type__ = "hook"
+ __version__ = "0.04"
+
+ __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):
self.account = self.core.accountManager.getAccountPlugin(self.__name__)
user = self.account.selectAccount()[0]
try:
- req = self.account.getAccountRequest(user)
+ req = self.account.getAccountRequest(user)
page = req.load("http://www.easybytez.com")
- found = re.search(r'</textarea>\s*Supported sites:(.*)', page)
- return found.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 1e2b62062..000000000
--- a/module/plugins/hooks/Ev0InFetcher.py
+++ /dev/null
@@ -1,90 +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/>.
-
- @author: mkaay
-"""
-from time import mktime, time
-
-from module.lib import feedparser
-from module.plugins.Hook import Hook
-
-
-class Ev0InFetcher(Hook):
- __name__ = "Ev0InFetcher"
- __version__ = "0.21"
- __description__ = """Checks rss feeds for Ev0.in"""
- __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")]
- __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 7be30f86e..54de8eb53 100644
--- a/module/plugins/hooks/ExpertDecoders.py
+++ b/module/plugins/hooks/ExpertDecoders.py
@@ -1,82 +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/>.
-
- @author: mkaay, RaNaN, zoidberg
-"""
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"
- __description__ = """Send captchas to expertdecoders.com"""
- __config__ = [("activated", "bool", "Activated", False),
- ("force", "bool", "Force CT even if client is connected", False),
+ __name__ = "ExpertDecoders"
+ __type__ = "hook"
+ __version__ = "0.03"
+
+ __config__ = [("force", "bool", "Force CT even if client is connected", False),
("passkey", "password", "Access key", "")]
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+
+ __description__ = """Send captchas to expertdecoders.com"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
API_URL = "http://www.fasttypers.org/imagepost.ashx"
+
+ #@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()
+ task.data['ticket'] = ticket = uuid4()
result = None
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
@@ -95,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 3d84dcc3d..a35e47c03 100644
--- a/module/plugins/hooks/ExternalScripts.py
+++ b/module/plugins/hooks/ExternalScripts.py
@@ -1,24 +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/>.
-
- @author: mkaay
- @interface-version: 0.1
-"""
-
import subprocess
+
+from itertools import chain
from os import listdir, access, X_OK, makedirs
from os.path import join, exists, basename, abspath
@@ -27,21 +11,38 @@ from module.utils import save_join
class ExternalScripts(Hook):
- __name__ = "ExternalScripts"
- __version__ = "0.23"
- __description__ = """Run external scripts"""
+ __name__ = "ExternalScripts"
+ __type__ = "hook"
+ __version__ = "0.25"
+
__config__ = [("activated", "bool", "Activated", True)]
- __author_name__ = ("mkaay", "RaNaN", "spoob")
- __author_mail__ = ("mkaay@mkaay.de", "ranan@pyload.org", "spoob@pyload.org")
- event_list = ["unrarFinished", "allDownloadsFinished", "allDownloadsProcessed"]
+ __description__ = """Run external scripts"""
+ __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"]
+
+
+ #@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] = []
@@ -51,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):
@@ -70,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 12e53fe50..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,44 +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"
+ __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"""
- __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)]
- __author_name__ = ("pyload Team", "AndroKev")
- __author_mail__ = ("admin<at>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)
@@ -93,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()
@@ -110,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
+ out = save_join(dl, p.folder, destination, "") #: force trailing slash
- if self.getConfig("destination") and self.getConfig("destination").lower() != "none":
+ if subfolder:
+ out = save_join(out, p.folder)
- out = save_join(dl, p.folder, self.getConfig("destination"), "")
- #relative to package folder if destination is relative, otherwise absolute path overwrites them
+ if not exists(out):
+ makedirs(out)
- if self.getConfig("subfolder"):
- out = join(out, fs_encode(p.folder))
-
- 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
+ files_ids = [(save_join(dl, p.folder, x['name']), x['id']) for x in p.getChildren().itervalues()]
+ 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()
+
+ 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"))
- if not plugin.checkArchive():
+ 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:
@@ -251,67 +355,87 @@ 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 self.config['permission']['change_file']:
if isfile(f):
- chmod(f, int(self.config["permission"]["file"], 8))
+ chmod(f, int(self.config['permission']['file'], 8))
elif isdir(f):
- chmod(f, int(self.config["permission"]["folder"], 8))
+ chmod(f, int(self.config['permission']['folder'], 8))
- if self.config["permission"]["change_dl"] and os.name != "nt":
- uid = getpwnam(self.config["permission"]["user"])[2]
- gid = getgrnam(self.config["permission"]["group"])[2]
+ if self.config['permission']['change_dl'] and os.name != "nt":
+ 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 558da1b86..73297eb23 100644
--- a/module/plugins/hooks/FastixRu.py
+++ b/module/plugins/hooks/FastixRu.py
@@ -1,27 +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"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+class FastixRu(MultiHook):
+ __name__ = "FastixRu"
+ __type__ = "hook"
+ __version__ = "0.03"
+
+ __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 7d4bcc852..0b71fc35b 100644
--- a/module/plugins/hooks/FreeWayMe.py
+++ b/module/plugins/hooks/FreeWayMe.py
@@ -1,40 +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/>.
-
- @author: Nicolas Giese
-"""
-
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"
- __description__ = """FreeWay.me hook plugin"""
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
+class FreeWayMe(MultiHook):
+ __name__ = "FreeWayMe"
+ __type__ = "hook"
+ __version__ = "0.12"
+
+ __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)]
- __author_name__ = "Nicolas Giese"
- __author_mail__ = "james@free-way.me"
+
+ __description__ = """FreeWay.me hook plugin"""
+ __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 38bcaf440..b0b59e2ba 100644
--- a/module/plugins/hooks/HotFolder.py
+++ b/module/plugins/hooks/HotFolder.py
@@ -1,83 +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/>.
-
- @author: RaNaN
- @interface-version: 0.2
-"""
-
-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"
- __description__ = """Observe folder and file for changes and add container and links"""
- __config__ = [("activated", "bool", "Activated", False),
- ("folder", "str", "Folder to observe", "container"),
+ __name__ = "HotFolder"
+ __type__ = "hook"
+ __version__ = "0.12"
+
+ __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")]
- __threaded__ = []
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.de"
+
+ __description__ = """Observe folder and file for changes and add container and links"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.de")]
+
def setup(self):
self.interval = 10
+
def periodical(self):
+ folder = fs_encode(self.getConfig("folder"))
- if not exists(join(self.getConfig("folder"), "finished")):
- makedirs(join(self.getConfig("folder"), "finished"))
+ 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 760c1a4df..efd4e411d 100644
--- a/module/plugins/hooks/IRCInterface.py
+++ b/module/plugins/hooks/IRCInterface.py
@@ -1,73 +1,62 @@
# -*- 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/>.
-
- @author: RaNaN
- @author: jeix
- @interface-version: 0.2
-"""
+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"
- __description__ = """Connect to irc and let owner perform different tasks"""
- __config__ = [("activated", "bool", "Activated", False),
- ("host", "str", "IRC-Server Address", "Enter your server here!"),
+ __name__ = "IRCInterface"
+ __type__ = "hook"
+ __version__ = "0.13"
+
+ __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),
("info_pack", "bool", "Inform about every package finished", True),
("captcha", "bool", "Send captcha requests", True)]
- __author_name__ = "Jeix"
- __author_mail__ = "Jeix@hasnomail.com"
+
+ __description__ = """Connect to irc and let owner perform different tasks"""
+ __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
- def coreReady(self):
- self.new_package = {}
- self.abort = False
+ #@TODO: Remove in 0.4.10
+ def initPeriodical(self):
+ pass
- self.links_added = 0
+
+ def coreReady(self):
+ self.abort = False
self.more = []
+ self.new_package = {}
self.start()
+
def packageFinished(self, pypack):
try:
if self.getConfig("info_pack"):
@@ -75,6 +64,7 @@ class IRCInterface(Thread, Hook):
except:
pass
+
def downloadFinished(self, pyfile):
try:
if self.getConfig("info_file"):
@@ -83,6 +73,7 @@ class IRCInterface(Thread, Hook):
except:
pass
+
def newCaptchaTask(self, task):
if self.getConfig("captcha") and task.isTextual():
task.handler.append(self)
@@ -95,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()
@@ -116,6 +112,7 @@ class IRCInterface(Thread, Hook):
print_exc()
self.sock.close()
+
def main_loop(self):
readbuffer = ""
while True:
@@ -154,34 +151,35 @@ 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():
+ if not msg['origin'].split("!", 1)[0] in self.getConfig("owner").split():
return
- if msg["target"].split("!", 1)[0] != self.getConfig("nick"):
+ if msg['target'].split("!", 1)[0] != self.getConfig("nick"):
return
- if msg["action"] != "PRIVMSG":
+ if msg['action'] != "PRIVMSG":
return
# HANDLE CTCP ANTI FLOOD/BOT PROTECTION
- if msg["text"] == "\x01VERSION\x01":
- self.logDebug("Sending CTCP VERSION.")
+ if msg['text'] == "\x01VERSION\x01":
+ 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.")
+ elif msg['text'] == "\x01TIME\x01":
+ 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
+ elif msg['text'] == "\x01LAG\x01":
+ self.logDebug("Received CTCP LAG") #: don't know how to answer
return
trigger = "pass"
args = None
try:
- temp = msg["text"].split()
+ temp = msg['text'].split()
trigger = temp[0]
if len(temp) > 1:
args = temp[1:]
@@ -192,9 +190,10 @@ class IRCInterface(Thread, Hook):
try:
res = handler(args)
for line in res:
- self.response(line, msg["origin"])
+ self.response(line, msg['origin'])
except Exception, e:
- self.logError("pyLoad IRC: " + repr(e))
+ self.logError(e)
+
def response(self, msg, origin=""):
if origin == "":
@@ -203,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."]
@@ -233,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."]
@@ -245,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!"]
@@ -256,27 +259,29 @@ class IRCInterface(Thread, Hook):
return lines
+
def event_info(self, args):
if not args:
- return ['ERROR: Use info like this: info <id>']
+ 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>']
+ return ["ERROR: Use packinfo like this: packinfo <id>"]
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."]
@@ -300,6 +305,7 @@ class IRCInterface(Thread, Hook):
return lines
+
def event_more(self, args):
if not self.more:
return ["No more information to display."]
@@ -310,20 +316,21 @@ class IRCInterface(Thread, Hook):
return lines
- def event_start(self, args):
- self.api.unpauseServer()
+ def event_start(self, args):
+ self.core.api.unpauseServer()
return ["INFO: Starting downloads."]
- def event_stop(self, args):
- self.api.pauseServer()
+ def event_stop(self, args):
+ 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". ',
- 'This will add the link <link> to to the package <package> / the package with id <id>!']
+ "This will add the link <link> to to the package <package> / the package with id <id>!"]
pack = args[0].strip()
links = [x.strip() for x in args[1:]]
@@ -332,58 +339,62 @@ 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."]
#TODO add links
- return ["INFO: Added %d links to Package %s [#%d]" % (len(links), pack["name"], id)]
+ return ["INFO: Added %d links to Package %s [#%d]" % (len(links), pack['name'], id)]
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:
@@ -396,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)",
@@ -415,8 +427,10 @@ class IRCInterface(Thread, Hook):
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 e2e9d93d5..f89d64c37 100644
--- a/module/plugins/hooks/ImageTyperz.py
+++ b/module/plugins/hooks/ImageTyperz.py
@@ -1,86 +1,90 @@
# -*- 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/>.
-
- @author: mkaay, RaNaN, zoidberg
-"""
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
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"
- __description__ = """Send captchas to ImageTyperz.com"""
- __config__ = [("activated", "bool", "Activated", False),
- ("username", "str", "Username", ""),
+ __name__ = "ImageTyperz"
+ __type__ = "hook"
+ __version__ = "0.05"
+
+ __config__ = [("username", "str", "Username", ""),
("passkey", "password", "Password", ""),
("force", "bool", "Force IT even if client is connected", False)]
- __author_name__ = ("RaNaN", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
+
+ __description__ = """Send captchas to ImageTyperz.com"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz")]
+
SUBMIT_URL = "http://captchatypers.com/Forms/UploadFileAndGetTextNEW.ashx"
RESPOND_URL = "http://captchatypers.com/Forms/SetBadImage.ashx"
GETCREDITS_URL = "http://captchatypers.com/Forms/RequestBalance.ashx"
+
+ #@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:
@@ -89,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
@@ -127,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
@@ -148,5 +158,5 @@ class ImageTyperz(Hook):
task.error = e.getCode()
return
- task.data["ticket"] = ticket
+ task.data['ticket'] = ticket
task.setResult(result)
diff --git a/module/plugins/hooks/LinkdecrypterCom.py b/module/plugins/hooks/LinkdecrypterCom.py
index dd9cd79f2..b0ce335d0 100644
--- a/module/plugins/hooks/LinkdecrypterCom.py
+++ b/module/plugins/hooks/LinkdecrypterCom.py
@@ -1,36 +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.
-
- 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/>.
-
- @author: zoidberg
-"""
-
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"
+ __name__ = "LinkdecrypterCom"
+ __type__ = "hook"
+ __version__ = "0.21"
+
__description__ = """Linkdecrypter.com hook plugin"""
- __config__ = [("activated", "bool", "Activated", False)]
- __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):
try:
@@ -38,15 +28,22 @@ 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)
- if not m:
+ 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
builtin = [name.lower() for name in self.core.pluginManager.crypterPlugins.keys()]
- builtin.extend(["downloadserienjunkiesorg"])
+ builtin.append("downloadserienjunkiesorg")
crypter_pattern = re.compile("(\w[\w.-]+)")
online = []
@@ -59,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)
+ 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 110731228..96bf1c0d1 100644
--- a/module/plugins/hooks/LinksnappyCom.py
+++ b/module/plugins/hooks/LinksnappyCom.py
@@ -1,26 +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"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+class LinksnappyCom(MultiHook):
+ __name__ = "LinksnappyCom"
+ __type__ = "hook"
+ __version__ = "0.02"
+
+ __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 0c3bb99f6..f3a0c31ea 100644
--- a/module/plugins/hooks/MegaDebridEu.py
+++ b/module/plugins/hooks/MegaDebridEu.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/>. #
-############################################################################
-
-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"
- __config__ = [("activated", "bool", "Activated", False),
- ("unloadFailing", "bool", "Revert to standard download if download fails", False)]
+class MegaDebridEu(MultiHook):
+ __name__ = "MegaDebridEu"
+ __type__ = "hook"
+ __version__ = "0.03"
+
+ __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":
+ 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 99b0aafc6..4de45f958 100644
--- a/module/plugins/hooks/MergeFiles.py
+++ b/module/plugins/hooks/MergeFiles.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/>.
-
- @author: and9000
-"""
+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
+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"
+ __name__ = "MergeFiles"
+ __type__ = "hook"
+ __version__ = "0.13"
+
+ __config__ = [("activated", "bool", "Activated", True)]
+
__description__ = """Merges parts splitted with hjsplit"""
- __config__ = [("activated", "bool", "Activated", False)]
- __threaded__ = ["packageFinished"]
- __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 data["name"][:-4] not in files:
- files[data["name"][:-4]] = []
- files[data["name"][:-4]].append(data["name"])
- files[data["name"][:-4]].sort()
- fid_dict[data["name"]] = fid
+ if re.search("\.\d{3}$", data['name']):
+ if data['name'][:-4] not in files:
+ files[data['name'][:-4]] = []
+ files[data['name'][:-4]].append(data['name'])
+ files[data['name'][:-4]].sort()
+ fid_dict[data['name']] = fid
download_folder = self.config['general']['download_folder']
@@ -58,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 f2dfb18ca..000000000
--- a/module/plugins/hooks/MultiDebridCom.py
+++ /dev/null
@@ -1,41 +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 b1635a588..105a42abd 100644
--- a/module/plugins/hooks/MultiHome.py
+++ b/module/plugins/hooks/MultiHome.py
@@ -1,67 +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/>.
-
- @author: mkaay
-"""
-
from time import time
from module.plugins.Hook import Hook
class MultiHome(Hook):
- __name__ = "MultiHome"
- __version__ = "0.11"
+ __name__ = "MultiHome"
+ __type__ = "hook"
+ __version__ = "0.12"
+
+ __config__ = [("interfaces", "str", "Interfaces", "None")]
+
__description__ = """Ip address changer"""
- __config__ = [("activated", "bool", "Activated", False),
- ("interfaces", "str", "Interfaces", "None")]
- __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):
self.register = {}
self.interfaces = []
self.parseInterfaces(self.getConfig("interfaces").split(";"))
if not self.interfaces:
- self.parseInterfaces([self.config["download"]["interface"]])
+ 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:
@@ -71,17 +67,21 @@ class MultiHome(Hook):
class Interface(object):
+
def __init__(self, adress):
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 0291738f5..5ec5b63b6 100644
--- a/module/plugins/hooks/MultishareCz.py
+++ b/module/plugins/hooks/MultishareCz.py
@@ -3,22 +3,25 @@
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"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+class MultishareCz(MultiHook):
+ __name__ = "MultishareCz"
+ __type__ = "hook"
+ __version__ = "0.05"
+
+ __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"'
+
def getHoster(self):
page = getURL("http://www.multishare.cz/monitoring/")
return re.findall(self.HOSTER_PATTERN, page)
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/OverLoadMe.py b/module/plugins/hooks/OverLoadMe.py
index e15d0b05f..378ce0a65 100644
--- a/module/plugins/hooks/OverLoadMe.py
+++ b/module/plugins/hooks/OverLoadMe.py
@@ -1,28 +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"
- __config__ = [("activated", "bool", "Activated", False),
- ("https", "bool", "Enable HTTPS", True),
+class OverLoadMe(MultiHook):
+ __name__ = "OverLoadMe"
+ __type__ = "hook"
+ __version__ = "0.02"
+
+ __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 57b188bb9..000000000
--- a/module/plugins/hooks/Premium4Me.py
+++ /dev/null
@@ -1,32 +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 9f1a70a70..b37728e06 100644
--- a/module/plugins/hooks/PremiumizeMe.py
+++ b/module/plugins/hooks/PremiumizeMe.py
@@ -1,25 +1,24 @@
# -*- 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"
- __description__ = """Premiumize.me hook plugin"""
+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)]
- __author_name__ = "Florian Franzen"
- __author_mail__ = "FlorianFranzen@gmail.com"
+ __description__ = """Premiumize.me hook plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Florian Franzen", "FlorianFranzen@gmail.com")]
+
def getHoster(self):
# If no accounts are available there will be no hosters available
@@ -31,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 54f814231..c54f7d445 100644
--- a/module/plugins/hooks/RPNetBiz.py
+++ b/module/plugins/hooks/RPNetBiz.py
@@ -1,22 +1,24 @@
# -*- 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"
- __description__ = """RPNet.biz hook plugin"""
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
+class RPNetBiz(MultiHook):
+ __name__ = "RPNetBiz"
+ __type__ = "hook"
+ __version__ = "0.11"
+
+ __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)]
- __author_name__ = "Dman"
- __author_mail__ = "dmanugm@gmail.com"
+
+ __description__ = """RPNet.biz hook plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Dman", "dmanugm@gmail.com")]
+
def getHoster(self):
# No hosts supported if no account
@@ -26,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")
@@ -45,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 566f9005f..066aa52c4 100644
--- a/module/plugins/hooks/RealdebridCom.py
+++ b/module/plugins/hooks/RealdebridCom.py
@@ -1,23 +1,24 @@
# -*- 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):
https = "https" if self.getConfig("https") else "http"
diff --git a/module/plugins/hooks/RehostTo.py b/module/plugins/hooks/RehostTo.py
index 6c3a77ca3..48afa2342 100644
--- a/module/plugins/hooks/RehostTo.py
+++ b/module/plugins/hooks/RehostTo.py
@@ -1,39 +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"]
+ self.ses = data['ses']
+ self.long_ses = data['long_ses']
- return MultiHoster.coreReady(self)
+ return MultiHook.coreReady(self)
diff --git a/module/plugins/hooks/ReloadCc.py b/module/plugins/hooks/ReloadCc.py
deleted file mode 100644
index 9960a2699..000000000
--- a/module/plugins/hooks/ReloadCc.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from module.plugins.internal.MultiHoster import MultiHoster
-
-from module.common.json_layer import json_loads
-from module.network.RequestFactory import getURL
-
-
-class ReloadCc(MultiHoster):
- __name__ = "ReloadCc"
- __version__ = "0.3"
- __type__ = "hook"
- __description__ = """Reload.cc hook plugin"""
-
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"),
- ("hosterList", "str", "Hoster list (comma separated)", "")]
-
- __author_name__ = "Reload Team"
- __author_mail__ = "hello@reload.cc"
-
- interval = 0 # Disable periodic calls
-
- def getHoster(self):
- # If no accounts are available there will be no hosters available
- if not self.account or not self.account.canUse():
- print "ReloadCc: No accounts available"
- return []
-
- # Get account data
- (user, data) = self.account.selectAccount()
-
- # Get supported hosters list from reload.cc using the json API v1
- query_params = dict(
- via='pyload',
- v=1,
- get_supported='true',
- get_traffic='true',
- user=user
- )
-
- try:
- query_params.update(dict(hash=self.account.infos[user]['pwdhash']))
- except Exception:
- query_params.update(dict(pwd=data['password']))
-
- answer = getURL("http://api.reload.cc/login", get=query_params)
- data = json_loads(answer)
-
- # If account is not valid thera are no hosters available
- if data['status'] != "ok":
- print "ReloadCc: Status is not ok: %s" % data['status']
- return []
-
- # Extract hosters from json file
- return data['msg']['supportedHosters']
-
- def coreReady(self):
- # Get account plugin and check if there is a valid account available
- self.account = self.core.accountManager.getAccountPlugin("ReloadCc")
- if not self.account.canUse():
- self.account = None
- self.logError("Please add a valid reload.cc account first and restart pyLoad.")
- return
-
- # Run the overwriten core ready which actually enables the multihoster hook
- return MultiHoster.coreReady(self)
diff --git a/module/plugins/hooks/RestartFailed.py b/module/plugins/hooks/RestartFailed.py
index 85553d738..07fb80967 100644
--- a/module/plugins/hooks/RestartFailed.py
+++ b/module/plugins/hooks/RestartFailed.py
@@ -1,57 +1,44 @@
# -*- 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/>.
-
- @author: Walter Purcaro
-"""
-
from module.plugins.Hook import Hook
class RestartFailed(Hook):
- __name__ = "RestartFailed"
- __version__ = "1.53"
+ __name__ = "RestartFailed"
+ __type__ = "hook"
+ __version__ = "1.57"
+
+ __config__ = [("interval", "int", "Check interval in minutes", 90)]
+
__description__ = """Periodically restart all failed downloads in queue"""
- __config__ = [("activated", "bool", "Activated", False),
- ("interval", "int", "Interval in minutes", 90)]
- __author_name__ = "Walter Purcaro"
- __author_mail__ = "vuolter@gmail.com"
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- event_list = ["pluginConfigChanged"]
- MIN_INTERVAL = 15 * 60 # seconds
+ # event_list = ["pluginConfigChanged"]
- def periodical(self):
- self.logDebug("Restart all failed downloads now")
- self.core.api.restartFailed()
+ MIN_INTERVAL = 15 * 60 #: 15m minimum check interval (value is in seconds)
- def restartPeriodical(self, interval):
- self.logDebug("Set periodical interval to %s seconds" % interval)
- if self.cb:
- self.core.scheduler.removeJob(self.cb)
- self.interval = interval
- self.cb = self.core.scheduler.addJob(interval, self._periodical, threaded=False)
def pluginConfigChanged(self, plugin, name, value):
- value *= 60
if name == "interval":
- if self.interval != value > self.MIN_INTERVAL:
- self.restartPeriodical(value)
+ interval = value * 60
+ if self.MIN_INTERVAL <= interval != self.interval:
+ self.core.scheduler.removeJob(self.cb)
+ self.interval = interval
+ self.initPeriodical()
else:
- self.logWarning("Cannot change interval: given value is equal to the current or \
- smaller than %s seconds" % self.MIN_INTERVAL)
+ self.logDebug("Invalid interval value, kept current")
+
+
+ def periodical(self):
+ self.logDebug(_("Restart failed downloads"))
+ self.core.api.restartFailed()
+
+
+ def setup(self):
+ self.interval = self.MIN_INTERVAL
+
def coreReady(self):
- self.pluginConfigChanged(plugin="RestartFailed", name="interval", value=self.getConfig("interval"))
+ 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 ca1122e45..10a1655c2 100644
--- a/module/plugins/hooks/SimplyPremiumCom.py
+++ b/module/plugins/hooks/SimplyPremiumCom.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/>. #
-############################################################################
-
-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 SimplyPremiumCom(MultiHook):
+ __name__ = "SimplyPremiumCom"
+ __type__ = "hook"
+ __version__ = "0.03"
-class SimplyPremiumCom(MultiHoster):
- __name__ = "SimplyPremiumCom"
- __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__ = """Simply-Premium.Com hook plugin"""
- __author_name__ = ("EvolutionClip")
- __author_mail__ = ("evolutionclip@live.de")
+
+ __description__ = """Simply-Premium.com hook plugin"""
+ __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['host'] for element in json_data['result']]
+ host_list = [element['regex'] for element in json_data['result']]
return host_list
diff --git a/module/plugins/hooks/SimplydebridCom.py b/module/plugins/hooks/SimplydebridCom.py
index a523d2404..48568f870 100644
--- a/module/plugins/hooks/SimplydebridCom.py
+++ b/module/plugins/hooks/SimplydebridCom.py
@@ -1,20 +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"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+class SimplydebridCom(MultiHook):
+ __name__ = "SimplydebridCom"
+ __type__ = "hook"
+ __version__ = "0.02"
+
+ __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 af6039ecd..1becb937a 100644
--- a/module/plugins/hooks/UnSkipOnFail.py
+++ b/module/plugins/hooks/UnSkipOnFail.py
@@ -1,97 +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.
+from module.PyFile import PyFile
+from module.plugins.Hook import Hook
- 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 UnSkipOnFail(Hook):
+ __name__ = "UnSkipOnFail"
+ __type__ = "hook"
+ __version__ = "0.05"
- @author: hgg
-"""
-from os.path import basename
+ __config__ = [("activated", "bool", "Activated", True)]
-from module.utils import fs_encode
-from module.plugins.Hook import Hook
-from module.PyFile import PyFile
+ __description__ = """Queue skipped duplicates when download fails"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
-class UnSkipOnFail(Hook):
- __name__ = 'UnSkipOnFail'
- __version__ = '0.01'
- __description__ = """When a download fails, restart skipped duplicates"""
- __config__ = [("activated", "bool", "Activated", True)]
- __author_name__ = "hagg"
- __author_mail__ = ""
+ #@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 4f8f11625..245264d44 100644
--- a/module/plugins/hooks/UnrestrictLi.py
+++ b/module/plugins/hooks/UnrestrictLi.py
@@ -1,41 +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"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+class UnrestrictLi(MultiHook):
+ __name__ = "UnrestrictLi"
+ __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),
("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 5f88ea6d0..c72699228 100644
--- a/module/plugins/hooks/UpdateManager.py
+++ b/module/plugins/hooks/UpdateManager.py
@@ -1,121 +1,223 @@
# -*- coding: utf-8 -*-
-import sys
+from __future__ import with_statement
+
import re
-from os import remove, stat
-from os.path import join, isfile
-from time import time
+import sys
+
+from operator import itemgetter
+from os import path, remove, stat
-from module.ConfigParser import IGNORE
from module.network.RequestFactory import getURL
-from module.plugins.Hook import threaded, Expose, Hook
+from module.plugins.Hook import Expose, Hook, threaded
+from module.utils import save_join
class UpdateManager(Hook):
- __name__ = "UpdateManager"
- __version__ = "0.16"
- __description__ = """Checks for updates"""
- __config__ = [("activated", "bool", "Activated", True),
- ("interval", "int", "Check interval in minutes", 480),
- ("debug", "bool", "Check for plugin changes when in debug mode", False)]
- __author_name__ = ("RaNaN", "stickell")
- __author_mail__ = ("ranan@pyload.org", "l.stickell@yahoo.it")
-
- URL = "http://updatemanager.pyload.org"
- MIN_TIME = 3 * 60 * 60 # 3h minimum check interval
-
- @property
- def debug(self):
- return self.core.debug and self.getConfig("debug")
+ __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 )]
+
+ __description__ = """ Check for updates """
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ # event_list = ["pluginConfigChanged"]
+
+ SERVER_URL = "http://updatemanager.pyload.org"
+ VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)')
+ MIN_INTERVAL = 3 * 60 * 60 #: 3h minimum check interval (value is in seconds)
+
+
+ def pluginConfigChanged(self, plugin, name, value):
+ if name == "interval":
+ interval = value * 60 * 60
+ if self.MIN_INTERVAL <= interval != self.interval:
+ self.core.scheduler.removeJob(self.cb)
+ self.interval = interval
+ self.initPeriodical()
+ else:
+ self.logDebug("Invalid interval value, kept current")
+
+ elif name == "reloadplugins":
+ if self.cb2:
+ self.core.scheduler.removeJob(self.cb2)
+ if value is True and self.core.debug:
+ self.periodical2()
+
+
+ def coreReady(self):
+ self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval"))
+ x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins"))
+ self.core.scheduler.addJob(10, x, threaded=False)
+
+
+ def unload(self):
+ self.pluginConfigChanged(self.__name__, "reloadplugins", False)
+
def setup(self):
- if self.debug:
- self.logDebug("Monitoring file changes")
- self.interval = 4
- self.last_check = 0 # timestamp of updatecheck
- self.old_periodical = self.periodical
- self.periodical = self.checkChanges
- self.mtimes = {} # recordes times
- else:
- self.interval = max(self.getConfig("interval") * 60, self.MIN_TIME)
+ 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.updated = False
- self.reloaded = True
- self.version = "None"
- self.info = {"pyload": False, "plugins": False}
+ def periodical2(self):
+ if not self.updating:
+ self.autoreloadPlugins()
+
+ self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False)
- @threaded
- def periodical(self):
- updates = self.checkForUpdate()
- if updates:
- self.checkPlugins(updates)
-
- if self.updated and not self.reloaded:
- self.info["plugins"] = True
- self.logInfo(_("*** Plugins have been updated, please restart pyLoad ***"))
- elif self.updated and self.reloaded:
- self.logInfo(_("Plugins updated and reloaded"))
- self.updated = False
- elif self.version == "None":
- self.logInfo(_("No plugin updates available"))
@Expose
- def recheckForUpdates(self):
- """recheck if updates are available"""
- self.periodical()
+ def autoreloadPlugins(self):
+ """ reload and reindex all modified plugins """
+ modules = filter(
+ lambda m: m and (m.__name__.startswith("module.plugins.") or
+ m.__name__.startswith("userplugins.")) and
+ m.__name__.count(".") >= 2, sys.modules.itervalues()
+ )
+
+ reloads = []
- def checkForUpdate(self):
- """checks if an update is available, return result"""
+ for m in modules:
+ root, type, name = m.__name__.rsplit(".", 2)
+ id = (type, name)
+ if type in self.core.pluginManager.plugins:
+ f = m.__file__.replace(".pyc", ".py")
+ if not path.isfile(f):
+ continue
+
+ mtime = stat(f).st_mtime
+
+ if id not in self.mtimes:
+ self.mtimes[id] = mtime
+ elif self.mtimes[id] < mtime:
+ reloads.append(id)
+ self.mtimes[id] = mtime
+
+ return True if self.core.pluginManager.reloadPlugins(reloads) else False
+
+
+ def periodical(self):
+ if not self.info['pyload'] and not (self.getConfig("nodebugupdate") and self.core.debug):
+ self.updateThread()
+
+
+ def server_request(self):
try:
- if self.version == "None": # No updated known
- version_check = getURL(self.URL, get={'v': self.core.api.getServerVersion()}).splitlines()
- self.version = version_check[0]
-
- # Still no updates, plugins will be checked
- if self.version == "None":
- self.logInfo(_("No Updates for pyLoad"))
- return version_check[1:]
-
- self.info["pyload"] = True
- self.logInfo(_("*** New pyLoad Version %s available ***") % self.version)
- self.logInfo(_("*** Get it here: http://pyload.org/download ***"))
+ return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines()
except:
- self.logWarning(_("Not able to connect server for updates"))
+ self.logWarning(_("Unable to contact server to get updates"))
- return None # Nothing will be done
- def checkPlugins(self, updates):
- """ checks for plugins updates"""
+ @threaded
+ def updateThread(self):
+ self.updating = True
- # plugins were already updated
- if self.info["plugins"]:
- return
+ 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
- reloads = []
- vre = re.compile(r'__version__.*=.*("|\')([0-9.]+)')
- url = updates[0]
- schema = updates[1].split("|")
- if 'BLACKLIST' in updates:
+ @Expose
+ def updatePlugins(self):
+ """ simple wrapper for calling plugin update quickly """
+ return self.update(onlyplugin=True)
+
+
+ @Expose
+ def update(self, onlyplugin=False):
+ """ check for updates """
+ data = self.server_request()
+
+ if not data:
+ exitcode = 0
+
+ elif data[0] == "None":
+ self.logInfo(_("No new pyLoad version available"))
+ updates = data[1:]
+ exitcode = self._updatePlugins(updates)
+
+ elif onlyplugin:
+ exitcode = 0
+
+ else:
+ newversion = data[0]
+ self.logInfo(_("*** New pyLoad Version %s available ***") % newversion)
+ self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***"))
+ exitcode = 3
+ self.info['pyload'] = True
+ self.info['version'] = newversion
+
+ return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available
+
+
+ def _updatePlugins(self, updates):
+ """ check for plugin updates """
+
+ if self.info['plugins']:
+ return False #: plugins were already updated
+
+ exitcode = 0
+ updated = []
+
+ url = updates[0]
+ schema = updates[1].split('|')
+
+ if "BLACKLIST" in updates:
blacklist = updates[updates.index('BLACKLIST') + 1:]
- updates = updates[2:updates.index('BLACKLIST')]
+ 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,
+ })
- for plugin in updates:
- info = dict(zip(schema, plugin.split("|")))
- filename = info["name"]
- prefix = info["type"]
- version = info["version"]
+ for plugin in sorted(upgradable, key=itemgetter("type", "name")):
+ filename = plugin['name']
+ 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:
@@ -123,79 +225,86 @@ class UpdateManager(Hook):
plugins = getattr(self.core.pluginManager, "%sPlugins" % type)
- if name in plugins:
- if float(plugins[name]["v"]) >= float(version):
- continue
+ oldver = float(plugins[name]['v']) if name in plugins else None
+ newver = float(version)
- if name in IGNORE or (type, name) in IGNORE:
+ if not oldver:
+ msg = "New plugin: [%(type)s] %(name)s (v%(newver).2f)"
+ elif newver > oldver:
+ msg = "New version of plugin: [%(type)s] %(name)s (v%(oldver).2f -> v%(newver).2f)"
+ else:
continue
- self.logInfo(_("New version of %(type)s|%(name)s : %(version).2f") % {
- "type": type,
- "name": name,
- "version": float(version)
- })
-
+ self.logInfo(_(msg) % {'type' : type,
+ 'name' : name,
+ 'oldver': oldver,
+ 'newver': newver})
try:
- content = getURL(url % info)
+ content = getURL(url % plugin)
+ m = self.VERSION.search(content)
+
+ if m and m.group(2) == version:
+ 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.logWarning(_("Error when updating %s") % filename, str(e))
- continue
+ self.logError(_("Error updating plugin: %s") % filename, str(e))
- m = vre.search(content)
- if not m or m.group(2) != version:
- self.logWarning(_("Error when updating %s") % name, _("Version mismatch"))
- continue
+ if updated:
+ reloaded = self.core.pluginManager.reloadPlugins(updated)
+ if reloaded:
+ self.logInfo(_("Plugins updated and reloaded"))
+ exitcode = 1
+ else:
+ self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***"))
+ self.info['plugins'] = True
+ exitcode = 2
+ else:
+ self.logInfo(_("No plugin updates available"))
- f = open(join("userplugins", prefix, filename), "wb")
- f.write(content)
- f.close()
- self.updated = True
+ return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required
- reloads.append((prefix, name))
- if blacklist:
- self.executeBlacklist(blacklist)
+ @Expose
+ def removePlugins(self, type_plugins):
+ """ delete plugins from disk """
- self.reloaded = self.core.pluginManager.reloadPlugins(reloads)
+ if not type_plugins:
+ return
- def executeBlacklist(self, blacklist):
- for b in blacklist:
- type, name = b.split('|')
- if isfile(join("userplugins", type, name)):
- self.logInfo(_("Removing blacklisted plugin %(type)s|%(name)s") % {
- "type": type,
- "name": name
- })
- remove(join("userplugins", type, name))
- if isfile(join("userplugins", type, name.replace('.py', '.pyc'))):
- remove(join("userplugins", type, name.replace('.py', '.pyc')))
+ self.logDebug("Requested deletion of plugins: %s" % type_plugins)
- def checkChanges(self):
- if self.last_check + max(self.getConfig("interval") * 60, self.MIN_TIME) < time():
- self.old_periodical()
- self.last_check = time()
+ removed = []
- modules = filter(
- lambda m: m and (m.__name__.startswith("module.plugins.") or m.__name__.startswith(
- "userplugins.")) and m.__name__.count(".") >= 2, sys.modules.itervalues())
+ for type, name in type_plugins:
+ err = False
+ file = name + ".py"
- reloads = []
+ for root in ("userplugins", path.join(pypath, "module", "plugins")):
- for m in modules:
- root, type, name = m.__name__.rsplit(".", 2)
- id = (type, name)
- if type in self.core.pluginManager.plugins:
- f = m.__file__.replace(".pyc", ".py")
- if not isfile(f):
- continue
+ filename = save_join(root, type, file)
+ try:
+ remove(filename)
+ except Exception, e:
+ self.logDebug("Error removing: %s" % path.basename(filename), str(e))
+ err = True
- mtime = stat(f).st_mtime
+ filename += "c"
+ if path.isfile(filename):
+ try:
+ if type == "hook":
+ self.manager.deactivateHook(name)
+ remove(filename)
+ except Exception, e:
+ self.logDebug("Error removing: %s" % path.basename(filename), str(e))
+ err = True
- if id not in self.mtimes:
- self.mtimes[id] = mtime
- elif self.mtimes[id] < mtime:
- reloads.append(id)
- self.mtimes[id] = mtime
+ if not err:
+ id = (type, name)
+ removed.append(id)
- self.core.pluginManager.reloadPlugins(reloads)
+ return removed #: return a list of the plugins successfully removed
diff --git a/module/plugins/hooks/Vipleech4uCom.py b/module/plugins/hooks/Vipleech4uCom.py
deleted file mode 100644
index b2156b017..000000000
--- a/module/plugins/hooks/Vipleech4uCom.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- coding: utf-8 -*-
-import re
-
-from module.network.RequestFactory import getURL
-from module.plugins.internal.MultiHoster import MultiHoster
-
-
-class Vipleech4uCom(MultiHoster):
- __name__ = "Vipleech4uCom"
- __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)", "")]
- __description__ = """Vipleech4u.com hook plugin"""
- __author_name__ = ("Kagenoshin")
- __author_mail__ = ("kagenoshin@gmx.ch")
-
- HOSTER_PATTERN = re.compile(r'align\s*?=\s*?["\']*?left.*?<\s*?strong\s*?>([^<]*?)<', re.I)
-
- def getHoster(self):
- hosters = {
- 'depositfiles': ['depositfiles.com', 'dfiles.eu'],
- 'uploaded': ['uploaded.to', 'uploaded.net', 'ul.to'],
- 'rapidggator': ['rapidgator.net'], # they have a typo it's called rapidgator
- 'freakshare': ['freakshare.net', 'freakshare.com'],
- 'filefactory': ['filefactory.com'],
- 'bitshare': ['bitshare.com'],
- 'share-online': ['share-online.biz', 'egoshare.com'],
- 'youtube': ['youtube.com'],
- 'turbobit': ['turbobit.net', 'unextfiles.com'],
- 'firedrive': ['firedrive.com', 'putlocker.com'],
- 'filepost': ['filepost.com', 'fp.io'],
- 'netload': ['netload.in'],
- 'uploadhero': ['uploadhero.com'],
- 'ryushare': ['ryushare.com'],
- }
-
- #check if the list is still valid
- self.check_for_new_or_removed_hosters(hosters)
-
- #build list
- hoster_list = []
-
- for item in hosters.itervalues():
- hoster_list.extend(item)
-
- return hoster_list
-
- def check_for_new_or_removed_hosters(self, hosters):
- #get the old hosters
- old_hosters = hosters.keys()
-
- #load the current hosters from vipleech4u.com
- page = getURL('http://vipleech4u.com/hosts.php')
- current_hosters = self.HOSTER_PATTERN.findall(page)
- current_hosters = [x.lower() for x in current_hosters]
-
- #let's look for new hosters
- new_hosters = []
-
- for hoster in current_hosters:
- if not hoster in old_hosters:
- new_hosters.append(hoster)
-
- #let's look for removed hosters
- removed_hosters = []
-
- for hoster in old_hosters:
- if not hoster in current_hosters:
- removed_hosters.append(hoster)
-
- if new_hosters:
- self.logDebug('The following new hosters were found on vipleech4u.com: %s' % str(new_hosters))
-
- if removed_hosters:
- self.logDebug('The following hosters were removed from vipleech4u.com: %s' % str(removed_hosters))
-
- if not (new_hosters and removed_hosters):
- self.logDebug('The hoster list is still valid.')
diff --git a/module/plugins/hooks/WindowsPhoneToastNotify.py b/module/plugins/hooks/WindowsPhoneToastNotify.py
index 7c005fcbb..ed305778c 100644
--- a/module/plugins/hooks/WindowsPhoneToastNotify.py
+++ b/module/plugins/hooks/WindowsPhoneToastNotify.py
@@ -1,40 +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/>.
-
- @author: RaNaN, Godofdream, zoidberg
-"""
-import time
import httplib
+import time
+
from module.plugins.Hook import Hook
class WindowsPhoneToastNotify(Hook):
- __name__ = "WindowsPhoneToastNotify"
- __version__ = "0.02"
- __description__ = """Send push notifications to Windows Phone"""
- __author_name__ = "Andy Voigt"
- __author_mail__ = "phone-support@hotmail.de"
- __config__ = [("activated", "bool", "Activated", False),
- ("force", "bool", "Force even if client is connected", False),
+ __name__ = "WindowsPhoneToastNotify"
+ __type__ = "hook"
+ __version__ = "0.03"
+
+ __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"""
+ __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'> "
@@ -42,6 +36,7 @@ class WindowsPhoneToastNotify(Hook):
"</wp:Toast> </wp:Notification>")
return myxml
+
def doRequest(self):
URL = self.getConfig("pushUrl")
request = self.getXmlData()
@@ -57,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 19ecc08b6..589143547 100644
--- a/module/plugins/hooks/XFileSharingPro.py
+++ b/module/plugins/hooks/XFileSharingPro.py
@@ -6,70 +6,126 @@ from module.plugins.Hook import Hook
class XFileSharingPro(Hook):
- __name__ = "XFileSharingPro"
- __version__ = "0.11"
- __type__ = "hook"
- __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)", "")]
- __description__ = """XFileSharingPro hook plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __name__ = "XFileSharingPro"
+ __type__ = "hook"
+ __version__ = "0.28"
+
+ __config__ = [("activated" , "bool", "Activated" , True ),
+ ("use_hoster_list" , "bool", "Load listed hosters only" , False),
+ ("use_crypter_list", "bool", "Load listed crypters only" , False),
+ ("use_builtin_list", "bool", "Load built-in plugin list" , True ),
+ ("hoster_list" , "str" , "Hoster list (comma separated)" , "" ),
+ ("crypter_list" , "str" , "Crypter list (comma separated)", "" )]
+
+ __description__ = """Load XFileSharingPro based hosters and crypter which don't need a own plugin to run"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ # event_list = ["pluginConfigChanged"]
+ regexp = {'hoster' : (r'https?://(?:www\.)?([\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')
+
+ 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(dict['pattern'])
+
def unload(self):
- dict = self.core.pluginManager.hosterPlugins['XFileSharingPro']
- dict["pattern"] = r"^unmatchable$"
- dict["re"] = re.compile(r"^unmatchable$")
+ # 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 5ecf4e153..bbeab4341 100644
--- a/module/plugins/hooks/XMPPInterface.py
+++ b/module/plugins/hooks/XMPPInterface.py
@@ -1,49 +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/>.
-
- @author: RaNaN
- @interface-version: 0.2
-"""
-
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"
- __description__ = """Connect to jabber and let owner perform different tasks"""
- __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"),
("info_file", "bool", "Inform about every file finished", False),
("info_pack", "bool", "Inform about every package finished", True),
("captcha", "bool", "Send captcha requests", True)]
- __author_name__ = "RaNaN"
- __author_mail__ = "RaNaN@pyload.org"
+
+ __description__ = """Connect to jabber and let owner perform different tasks"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "RaNaN@pyload.org")]
+
implements(IMessageHandlersProvider)
+
def __init__(self, core, manager):
IRCInterface.__init__(self, core, manager)
@@ -72,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"):
@@ -84,6 +72,7 @@ class XMPPInterface(IRCInterface, JabberClient):
except:
pass
+
def downloadFinished(self, pyfile):
try:
if self.getConfig("info_file"):
@@ -92,45 +81,50 @@ 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.
The handlers returned will be called when matching message is received
in a client session."""
- return [
- ("normal", self.message),
- ]
+ 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
@@ -174,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)
@@ -203,9 +199,11 @@ class XMPPInterface(IRCInterface, JabberClient):
stream.send(m)
+
def beforeReconnecting(self, ip):
self.disconnect()
+
def afterReconnecting(self, ip):
self.connect()
@@ -218,26 +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),
- ]
+ 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 4dee83ccb..6ca696f38 100644
--- a/module/plugins/hooks/ZeveraCom.py
+++ b/module/plugins/hooks/ZeveraCom.py
@@ -1,20 +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"
- __config__ = [("activated", "bool", "Activated", False),
- ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+class ZeveraCom(MultiHook):
+ __name__ = "ZeveraCom"
+ __type__ = "hook"
+ __version__ = "0.03"
+
+ __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 11ee8b7d3..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 970ac8081..d0d8e7cc8 100644
--- a/module/plugins/hoster/BasePlugin.py
+++ b/module/plugins/hoster/BasePlugin.py
@@ -1,113 +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"])
+ 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)
-
- # self.load does not raise a BadHeader on 404 responses, do it here
- if 'code' in header and header['code'] == 404:
- raise BadHeader(404)
+ 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)
- 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 b080eb386..0929ece01 100644
--- a/module/plugins/hoster/BayfilesCom.py
+++ b/module/plugins/hoster/BayfilesCom.py
@@ -1,97 +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"
- @author: zoidberg
-"""
+ __pattern__ = r'https?://(?:www\.)?bayfiles\.(com|net)/file/(?P<ID>\w+/\w+/[^/]+)'
-import re
-from time import time
-
-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.06"
__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>'
- FILE_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+);'
- 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):
- found = re.search(self.WAIT_PATTERN, self.html)
- if found:
- self.wait(int(found.group(1)) * 60)
- self.retry()
-
- # Get download token
- found = re.search(self.VARS_PATTERN, self.html)
- if not found:
- self.parseError('VARS')
- vfid, delay = found.groups()
-
- response = json_loads(self.load('https://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('https://bayfiles.com/ajax_download', get={
- "token": response['token'],
- "action": "getLink",
- "vfid": vfid})
-
- # Get final link and download
- found = re.search(self.LINK_PATTERN, self.html)
- if not found:
- self.parseError("Free link")
- self.startDownload(found.group(1))
-
- def handlePremium(self):
- found = re.search(self.PREMIUM_LINK_PATTERN, self.html)
- if not found:
- self.parseError("Premium link")
- self.startDownload(found.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 55f3f33b9..9ca4b4b1a 100644
--- a/module/plugins/hoster/BezvadataCz.py
+++ b/module/plugins/hoster/BezvadataCz.py
@@ -1,65 +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/>.
-
- @author: zoidberg
-"""
-
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")]
+
+
+ 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>'
- FILE_NAME_PATTERN = r'<p><b>Soubor: (?P<N>[^<]+)</b></p>'
- FILE_SIZE_PATTERN = r'<li><strong>Velikost:</strong> (?P<S>[^<]+)</li>'
- FILE_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
- found = re.search(r'<a class="stahnoutSoubor".*?href="(.*?)"', self.html)
- if not found:
- self.parseError("page1 URL")
- url = "http://bezvadata.cz%s" % found.group(1)
+ m = re.search(r'<a class="stahnoutSoubor".*?href="(.*?)"', self.html)
+ if m is None:
+ self.error(_("Page 1 URL not found"))
+ url = "http://bezvadata.cz%s" % m.group(1)
#captcha form
self.html = self.load(url)
self.checkErrors()
- for _ in xrange(5):
+ for _i in xrange(5):
action, inputs = self.parseHtmlForm('frm-stahnoutFreeForm')
if not inputs:
- self.parseError("FreeForm")
+ self.error(_("FreeForm"))
- found = re.search(r'<img src="data:image/png;base64,(.*?)"', self.html)
- if not found:
- self.parseError("captcha img")
+ m = re.search(r'<img src="data:image/png;base64,(.*?)"', self.html)
+ if m is None:
+ self.error(_("Wrong captcha image"))
#captcha image is contained in html page as base64encoded data but decryptCaptcha() expects image url
self.load, proper_load = self.loadcaptcha, self.load
try:
- inputs['captcha'] = self.decryptCaptcha(found.group(1), imgtype='png')
+ inputs['captcha'] = self.decryptCaptcha(m.group(1), imgtype='png')
finally:
self.load = proper_load
@@ -69,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()
- found = re.search(r'<a class="stahnoutSoubor2" href="(.*?)">', self.html)
- if not found:
- self.parseError("page2 URL")
- url = "http://bezvadata.cz%s" % found.group(1)
+ m = re.search(r'<a class="stahnoutSoubor2" href="(.*?)">', self.html)
+ if m is None:
+ self.error(_("Page 2 URL not found"))
+ url = "http://bezvadata.cz%s" % m.group(1)
self.logDebug("DL URL %s" % url)
#countdown
- found = re.search(r'id="countdown">(\d\d):(\d\d)<', self.html)
- wait_time = (int(found.group(1)) * 60 + int(found.group(2)) + 1) if found else 120
+ m = re.search(r'id="countdown">(\d\d):(\d\d)<', self.html)
+ wait_time = (int(m.group(1)) * 60 + int(m.group(2))) if m else 120
self.wait(wait_time, False)
self.download(url)
+
def checkErrors(self):
if 'images/button-download-disable.png' in self.html:
- self.longWait(5 * 60, 24) # parallel dl limit
+ 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 d4b0668c0..1c5c53f55 100644
--- a/module/plugins/hoster/BitshareCom.py
+++ b/module/plugins/hoster/BitshareCom.py
@@ -4,71 +4,83 @@ from __future__ import with_statement
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 BitshareCom(SimpleHoster):
- __name__ = "BitshareCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?bitshare\.com/(files/(?P<id1>[a-zA-Z0-9]+)(/(?P<name>.*?)\.html)?|\?f=(?P<id2>[a-zA-Z0-9]+))'
- __version__ = "0.49"
+ __name__ = "BitshareCom"
+ __type__ = "hoster"
+ __version__ = "0.51"
+
+ __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")]
+
+
+ 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'
- HOSTER_DOMAIN = "bitshare.com"
- FILE_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_INFO_PATTERN = r'Downloading (?P<N>.+) - (?P<S>[\d.]+) (?P<U>\w+)</h1>'
- 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!"
def setup(self):
- self.req.cj.setCookie(self.HOSTER_DOMAIN, "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
self.html = self.load(pyfile.url, ref=False, decode=True)
# Check offline
- if re.search(self.FILE_OFFLINE_PATTERN, self.html):
+ if re.search(self.OFFLINE_PATTERN, self.html):
self.offline()
# Check Traffic used up
if re.search(self.TRAFFIC_USED_UP, self.html):
- self.logInfo("Your Traffic is used up for today. Wait 1800 seconds or reconnect!")
- self.logDebug("Waiting %d seconds." % 1800)
+ 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
@@ -79,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
@@ -100,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 efaf8e5f7..949a021dd 100644
--- a/module/plugins/hoster/CatShareNet.py
+++ b/module/plugins/hoster/CatShareNet.py
@@ -1,38 +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>'
+
+ 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">'
+
+
+ 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()
- FILE_INFO_PATTERN = r'<h3 class="pull-left"[^>]+>(?P<N>.*)</h3>\s+<h3 class="pull-right"[^>]+>(?P<S>.*)</h3>'
- FILE_OFFLINE_PATTERN = r'Podany plik zosta'
- SECONDS_PATTERN = 'var\s+count\s+=\s+(\d+);'
- RECAPTCHA_KEY = "6Lfln9kSAAAAANZ9JtHSOgxUPB9qfDFeLUI_QMEy"
def handleFree(self):
- found = re.search(self.SECONDS_PATTERN, self.html)
- seconds = int(found.group(1))
- self.logDebug("Seconds found", seconds)
- self.wait(seconds + 1)
+ m = re.search(self.SECONDS_PATTERN, self.html)
+ 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 e882f5cea..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>.*?)\)'
- DIRECT_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 3cd2be59d..e5f94800b 100644
--- a/module/plugins/hoster/CrockoCom.py
+++ b/module/plugins/hoster/CrockoCom.py
@@ -2,63 +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>'
- FILE_OFFLINE_PATTERN = r"<h1>Sorry,<br />the page you're looking for <br />isn't here.</h1>|File not found"
- DOWNLOAD_URL_PATTERN = r"window.location ='([^']+)';"
- 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):
- found = re.search(self.CAPTCHA_URL_PATTERN, self.html)
- if found:
- url, wait_time = 'http://crocko.com' + found.group(1), found.group(2)
+ for _i in xrange(5):
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
+ if m:
+ url, wait_time = 'http://crocko.com' + m.group(1), int(m.group(2))
self.wait(wait_time)
self.html = self.load(url)
else:
break
- found = re.search(self.CAPTCHA_KEY_PATTERN, self.html)
- if not found:
- self.parseError('Captcha KEY')
- captcha_key = found.group(1)
+ m = re.search(self.FORM_PATTERN, self.html, re.S)
+ if m is None:
+ self.error(_("FORM_PATTERN not found"))
- found = re.search(self.FORM_PATTERN, self.html, re.DOTALL)
- if not found:
- self.parseError('ACTION')
- action, form = found.groups()
+ 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":
@@ -66,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 a462deaff..aa381d712 100644
--- a/module/plugins/hoster/CzshareCom.py
+++ b/module/plugins/hoster/CzshareCom.py
@@ -1,97 +1,88 @@
# -*- 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/>.
-
- @author: zoidberg
-"""
-
-# Test links (random.bin):
+#
+# Test links:
# http://czshare.com/5278880/random.bin
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError
+
+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>'
- FILE_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/')]
- SH_CHECK_TRAFFIC = True
+ NAME_PATTERN = r'<div class="tab" id="parameters">\s*<p>\s*Cel. n.zev: <a href=[^>]*>(?P<N>[^<]+)</a>'
+ SIZE_PATTERN = r'<div class="tab" id="category">(?:\s*<p>[^\n]*</p>)*\s*Velikost:\s*(?P<S>[\d .,]+)(?P<U>[\w^_]+)\s*</div>'
+ OFFLINE_PATTERN = r'<div class="header clearfix">\s*<h2 class="red">'
+
+ SIZE_REPLACEMENTS = [(' ', '')]
+ URL_REPLACEMENTS = [(r'http://[^/]*/download.php\?.*?id=(\w+).*', r'http://sdilej.cz/\1/x/')]
+
+ CHECK_TRAFFIC = True
+
+ FREE_URL_PATTERN = r'<a href="([^"]+)" class="page-download">[^>]*alt="([^"]+)" /></a>'
+ FREE_FORM_PATTERN = r'<form action="download\.php" method="post">\s*<img src="captcha\.php" id="captcha" />(.*?)</form>'
+ PREMIUM_FORM_PATTERN = r'<form action="/profi_down\.php" method="post">(.*?)</form>'
+ FORM_INPUT_PATTERN = r'<input[^>]* name="([^"]+)" value="([^"]+)"[^>]*/>'
+ MULTIDL_PATTERN = r'<p><font color=\'red\'>Z[^<]*PROFI.</font></p>'
+ USER_CREDIT_PATTERN = r'<div class="credit">\s*kredit: <strong>([\d .,]+)(\w+)</strong>\s*</div><!-- .credit -->'
- 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 -->'
def checkTrafficLeft(self):
# check if user logged in
- found = re.search(self.USER_CREDIT_PATTERN, self.html)
- if not found:
+ m = re.search(self.USER_CREDIT_PATTERN, self.html)
+ if m is None:
self.account.relogin(self.user)
self.html = self.load(self.pyfile.url, cookies=True, decode=True)
- found = re.search(self.USER_CREDIT_PATTERN, self.html)
- if not found:
+ m = re.search(self.USER_CREDIT_PATTERN, self.html)
+ if m is None:
return False
# check user credit
try:
- credit = parseFileSize(found.group(1).replace(' ', ''), found.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))
+ credit = parseFileSize(m.group(1).replace(' ', ''), m.group(2))
+ self.logInfo(_("Premium download for %i KiB of Credit") % (self.pyfile.size / 1024))
+ self.logInfo(_("User %s has %i KiB left") % (self.user, credit / 1024))
if credit < self.pyfile.size:
- self.logInfo("Not enough credit to download file %s" % self.pyfile.name)
+ 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
- found = re.search(self.FREE_URL_PATTERN, self.html)
- if found is None:
- raise PluginParseError('Free URL')
- parsed_url = "http://sdilej.cz" + found.group(1)
+ m = re.search(self.FREE_URL_PATTERN, self.html)
+ if m is None:
+ self.error(_("FREE_URL_PATTERN not found"))
+ parsed_url = "http://sdilej.cz" + m.group(1)
self.logDebug("PARSED_URL:" + parsed_url)
# get download ticket and parse html
@@ -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)
- raise PluginParseError('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,34 +111,35 @@ class CzshareCom(SimpleHoster):
self.correctCaptcha()
break
else:
- self.fail("No valid captcha code entered")
+ self.fail(_("No valid captcha code entered"))
- found = re.search("countdown_number = (\d+);", self.html)
- self.setWait(int(found.group(1)) if found else 50)
+ m = re.search("countdown_number = (\d+);", self.html)
+ self.setWait(int(m.group(1)) if m else 50)
# download the file, destination is determined by pyLoad
self.logDebug("WAIT URL", self.req.lastEffectiveURL)
- found = re.search("free_wait.php\?server=(.*?)&(.*)", self.req.lastEffectiveURL)
- if not found:
- raise PluginParseError('Download URL')
+ m = re.search("free_wait.php\?server=(.*?)&(.*)", self.req.lastEffectiveURL)
+ if m is None:
+ self.error(_("Download URL not found"))
- url = "http://%s/download.php?%s" % (found.group(1), found.group(2))
+ url = "http://%s/download.php?%s" % (m.group(1), m.group(2))
self.wait()
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 17e1ecf92..dc42d1f60 100644
--- a/module/plugins/hoster/DailymotionCom.py
+++ b/module/plugins/hoster/DailymotionCom.py
@@ -1,49 +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/>.
-#
-# @author: Walter Purcaro
-############################################################################
-
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"]:
+ if "error" in info or info['access_error']:
status = "offline"
else:
- status = info["status"]
+ status = info['status']
if status in ("ready", "published"):
status = "online"
elif status in ("waiting", "processing"):
@@ -52,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", "HD 720p")]
+ __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)]):
@@ -102,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 0c872b419..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>'
- FILE_OFFLINE_PATTERN = ur'Az adott f\xe1jl nem l\xe9tezik'
- DIRECT_LINK_PATTERN = r'<div class="download_box_button"><a href="([^"]+)">'
- def handleFree(self):
+ 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 setup(self):
self.resumeDownload = True
- self.html = self.load(self.pyfile.url, decode=True)
+ self.multiDL = self.premium
+
- m = re.search(self.DIRECT_LINK_PATTERN, self.html)
- if m:
- url = m.group(1)
- self.logDebug('Direct link: ' + url)
- else:
- self.parseError('Unable to get direct link')
+ def handleFree(self):
+ m = re.search(self.LINK_PATTERN, self.html)
+ 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 291dcaf55..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.
+from module.plugins.internal.SimpleHoster import SimpleHoster, 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/>.
-
- @author: zoidberg
-"""
-
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError
+class DataportCz(SimpleHoster):
+ __name__ = "DataportCz"
+ __type__ = "hoster"
+ __version__ = "0.40"
+ __pattern__ = r'http://(?:www\.)?dataport\.cz/file/(.+)'
-class DataportCz(SimpleHoster):
- __name__ = "DataportCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?dataport.cz/file/(.*)'
- __version__ = "0.37"
__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>'
- FILE_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:
- raise PluginParseError('free_download_form')
+ self.error(_("free_download_form"))
- if "captchaId" in inputs and inputs["captchaId"] in captchas:
- inputs['captchaCode'] = captchas[inputs["captchaId"]]
+ if "captchaId" in inputs and inputs['captchaId'] in captchas:
+ inputs['captchaCode'] = captchas[inputs['captchaId']]
else:
- raise PluginParseError('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":
- raise PluginParseError('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 223138592..e4bff8458 100644
--- a/module/plugins/hoster/DateiTo.py
+++ b/module/plugins/hoster/DateiTo.py
@@ -1,52 +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/>.
-
- @author: zoidberg
-"""
-
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>.*?)</'
- FILE_OFFLINE_PATTERN = r'>Datei wurde nicht gefunden<|>Bitte wÀhle deine Datei aus... <'
- PARALELL_PATTERN = r'>Du lÀdst bereits eine Datei herunter<'
+ 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... <'
+
+ WAIT_PATTERN = r'countdown\({seconds: (\d+)'
+ MULTIDL_PATTERN = r'>Du lÀdst bereits eine Datei herunter<'
- WAIT_PATTERN = r'countdown\({seconds: (\d+)'
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,39 +45,38 @@ class DateiTo(SimpleHoster):
elif data['P'] == 'IV':
break
- found = re.search(self.DATA_PATTERN, self.html)
- if not found:
- self.parseError('data')
- url = 'http://datei.to/' + found.group(1)
- data = dict(x.split('=') for x in found.group(2).split('&'))
+ m = re.search(self.DATA_PATTERN, self.html)
+ if m is None:
+ self.error(_("data"))
+ url = 'http://datei.to/' + m.group(1)
+ data = dict(x.split('=') for x in m.group(2).split('&'))
if url.endswith('recaptcha.php'):
- found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html)
- recaptcha_key = found.group(1) if found 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):
- found = re.search(self.PARALELL_PATTERN, self.html)
- if found:
- found = re.search(self.WAIT_PATTERN, self.html)
- wait_time = int(found.group(1)) if found else 30
- self.wait(wait_time + 1, False)
- self.retry()
+ m = re.search(self.MULTIDL_PATTERN, self.html)
+ if m:
+ m = re.search(self.WAIT_PATTERN, self.html)
+ wait_time = int(m.group(1)) if m else 30
+
+ errmsg = self.info['error'] = _("Parallel downloads")
+ self.retry(wait_time=wait_time, reason=errmsg)
+
+ self.info.pop('error', None)
+
def doWait(self):
- found = re.search(self.WAIT_PATTERN, self.html)
- wait_time = int(found.group(1)) if found else 30
+ 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 eed53b1e1..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 11b4f4112..6588a3b37 100644
--- a/module/plugins/hoster/DepositfilesCom.py
+++ b/module/plugins/hoster/DepositfilesCom.py
@@ -1,111 +1,123 @@
# -*- coding: utf-8 -*-
import re
+
from urllib import unquote
-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 DepositfilesCom(SimpleHoster):
- __name__ = "DepositfilesCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?(depositfiles\.com|dfiles\.(eu|ru))(/\w{1,3})?/files/[\w]+'
- __version__ = "0.46"
+ __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")
- __author_mail__ = ("spoob@pyload.org", "zoidberg@mujmail.cz")
-
- FILE_SIZE_PATTERN = r': <b>(?P<S>[0-9.]+)&nbsp;(?P<U>[kKMG])i?B</b>'
- FILE_NAME_PATTERN = r'<script type="text/javascript">eval\( unescape\(\'(?P<N>.*?)\''
- FILE_OFFLINE_PATTERN = r'<span class="html_download_api-not_exists"></span>'
- FILE_URL_REPLACEMENTS = [(r"\.com(/.*?)?/files", ".com/en/files"), (r"\.html$", "")]
- FILE_NAME_REPLACEMENTS = [(r'\%u([0-9A-Fa-f]{4})', lambda m: unichr(int(m.group(1), 16))),
+ __license__ = "GPLv3"
+ __authors__ = [("spoob", "spoob@pyload.org"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ NAME_PATTERN = r'<script type="text/javascript">eval\( unescape\(\'(?P<N>.*?)\''
+ SIZE_PATTERN = r': <b>(?P<S>[\d.,]+)&nbsp;(?P<U>[\w^_]+)</b>'
+ OFFLINE_PATTERN = r'<span class="html_download_api-not_exists"></span>'
+
+ NAME_REPLACEMENTS = [(r'\%u([0-9A-Fa-f]{4})', lambda m: unichr(int(m.group(1), 16))),
(r'.*<b title="(?P<N>[^"]+).*', "\g<N>")]
+ URL_REPLACEMENTS = [(__pattern__ + ".*", "https://dfiles.eu/files/\g<ID>")]
+
+ COOKIES = [("dfiles.eu", "lang_current", "en")]
+
+ 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="(.+?)"'
- RECAPTCHA_PATTERN = r"Recaptcha.create\('([^']+)'"
- DOWNLOAD_LINK_PATTERN = r'<form id="downloader_file_form" action="(http://.+?\.(dfiles\.eu|depositfiles\.com)/.+?)" method="post"'
def handleFree(self):
self.html = self.load(self.pyfile.url, post={"gateway_result": "1"}, cookies=True)
- if re.search(self.FILE_OFFLINE_PATTERN, self.html):
- self.offline()
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)
if wait:
self.setWait(int(wait.group(1)))
- found = re.search(r"var fid = '(\w+)';", self.html)
- if not found:
+ m = re.search(r"var fid = '(\w+)';", self.html)
+ if m is None:
self.retry(wait_time=5)
- params = {'fid': found.group(1)}
+ params = {'fid': m.group(1)}
self.logDebug("FID: %s" % params['fid'])
- captcha_key = '6LdRTL8SAAAAAE9UOdWZ4d0Ky-aeA7XfSqyWDM2m'
- found = re.search(self.RECAPTCHA_PATTERN, self.html)
- if found:
- captcha_key = found.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):
- self.html = self.load("http://depositfiles.com/get_file.php", get=params)
+ 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)
self.logDebug(params)
continue
- found = re.search(self.DOWNLOAD_LINK_PATTERN, self.html)
- if found:
+ m = re.search(self.FREE_LINK_PATTERN, self.html)
+ if m:
if 'response' in params:
self.correctCaptcha()
- link = unquote(found.group(1))
+ link = unquote(m.group(1))
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):
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)
self.retry()
- link = unquote(
- re.search('<div id="download_url">\s*<a href="(http://.+?\.depositfiles.com/.+?)"', self.html).group(1))
- self.download(link, disposition=True)
+ else:
+ link = re.search(self.PREMIUM_LINK_PATTERN, self.html)
+ mirror = re.search(self.PREMIUM_MIRROR_PATTERN, self.html)
+ if link:
+ dlink = link.group(1)
+ elif mirror:
+ dlink = mirror.group(1)
+ else:
+ 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 998dcd606..793c81b1c 100644
--- a/module/plugins/hoster/DlFreeFr.py
+++ b/module/plugins/hoster/DlFreeFr.py
@@ -1,23 +1,26 @@
# -*- 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):
+
def __init__(self, bucket=None, options={}):
Browser.__init__(self, bucket, options)
+
def load(self, *args, **kwargs):
post = kwargs.get("post")
- if post is None:
- if len(args) > 2:
- post = args[2]
+
+ if post is None and len(args) > 2:
+ post = args[2]
+
if post:
self.http.c.setopt(pycurl.FOLLOWLOCATION, 0)
self.http.c.setopt(pycurl.POST, 1)
@@ -26,114 +29,46 @@ class CustomBrowser(Browser):
self.http.c.setopt(pycurl.FOLLOWLOCATION, 1)
self.http.c.setopt(pycurl.POST, 0)
self.http.c.setopt(pycurl.CUSTOMREQUEST, "GET")
- return Browser.load(self, *args, **kwargs)
-
-
-class 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
- found = re.search(self.ADYOULIKE_INPUT_PATTERN, html)
- if found:
- adyoulike_data_string = found.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)
+ return Browser.load(self, *args, **kwargs)
- 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})
- found = re.search(self.ADYOULIKE_CHALLENGE_PATTERN, res)
- challenge_string = None
- if found:
- challenge_string = found.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"]
- found = re.search(u".*«(.*)».*", instructions_visual)
- if found:
- response = found.group(1).strip()
- else:
- self.plugin.fail("Can't parse instructions visual")
- except KeyError:
- self.plugin.fail("No instructions visual")
+class DlFreeFr(SimpleHoster):
+ __name__ = "DlFreeFr"
+ __type__ = "hoster"
+ __version__ = "0.26"
- #TODO: Supports captcha
+ __pattern__ = r'http://(?:www\.)?dl\.free\.fr/(\w+|getfile\.pl\?file=/\w+)'
- if not response:
- self.plugin.fail("AdYouLike result failed")
+ __description__ = """Dl.free.fr hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("the-razer", "daniel_ AT gmx DOT net"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("Toilal", "toilal.dev@gmail.com")]
- return {"_ayl_captcha_engine": self.engine,
- "_ayl_env": ayl["all"]["env"],
- "_ayl_tid": challenge["tid"],
- "_ayl_token_challenge": challenge["token"],
- "_ayl_response": response}
+ 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;'
-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")
-
- FILE_NAME_PATTERN = r"Fichier:</td>\s*<td[^>]*>(?P<N>[^>]*)</td>"
- FILE_SIZE_PATTERN = r"Taille:</td>\s*<td[^>]*>(?P<S>[\d.]+[KMG])o"
- FILE_OFFLINE_PATTERN = r"Erreur 404 - Document non trouv|Fichier inexistant|Le fichier demand&eacute; n'a pas &eacute;t&eacute; trouv&eacute;"
- #FILE_URL_PATTERN = r'href="(?P<url>http://.*?)">T&eacute;l&eacute;charger ce fichier'
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)
@@ -145,35 +80,35 @@ 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()
if headers.get("code") == 302 and "set-cookie" in headers and "location" in headers:
- found = re.search("(.*?)=(.*?); path=(.*?); domain=(.*?)", headers.get("set-cookie"))
+ m = re.search("(.*?)=(.*?); path=(.*?); domain=(.*?)", headers.get("set-cookie"))
cj = CookieJar(__name__)
- if found:
- cj.setCookie(found.group(4), found.group(1), found.group(2), found.group(3))
+ 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 0ea9b186f..cd54bdc70 100644
--- a/module/plugins/hoster/EasybytezCom.py
+++ b/module/plugins/hoster/EasybytezCom.py
@@ -1,46 +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"
- @author: zoidberg
-"""
+ __pattern__ = r'http://(?:www\.)?easybytez\.com/\w{12}'
-from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
-
-
-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>'
- FILE_OFFLINE_PATTERN = r'<h1>File not available</h1>'
+ HOSTER_DOMAIN = "easybytez.com"
- DIRECT_LINK_PATTERN = r'(http://(\w+\.(easyload|easybytez|zingload)\.(com|to)|\d+\.\d+\.\d+\.\d+)/files/\d+/\w+/[^"<]+)'
- OVR_DOWNLOAD_LINK_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)'
- OVR_KILL_LINK_PATTERN = r'<h2>Delete 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 f2d0fa206..eb9338871 100644
--- a/module/plugins/hoster/EdiskCz.py
+++ b/module/plugins/hoster/EdiskCz.py
@@ -1,53 +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/>.
-
- @author: zoidberg
-"""
-
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")]
+
+
+ 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>'
- URL_PATTERN = r'<form name = "formular" action = "([^"]+)" method = "post">'
- FILE_INFO_PATTERN = r'<span class="fl" title="(?P<N>[^"]+)">\s*.*?\((?P<S>[0-9.]*) (?P<U>[kKMG])i?B\)</h1></span>'
ACTION_PATTERN = r'/en/download/(\d+/.*\.html)'
- DLLINK_PATTERN = r'http://.*edisk.cz.*\.html'
- FILE_OFFLINE_PATTERN = r'<h3>This file does not exist due to one of the following:</h3><ul><li>'
+ 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)
- found = re.search(self.ACTION_PATTERN, url)
- if found is None:
- self.parseError("ACTION")
- action = found.group(1)
+ m = re.search(self.ACTION_PATTERN, url)
+ if m is None:
+ self.error(_("ACTION_PATTERN not found"))
+ action = m.group(1)
self.html = self.load(url, decode=True)
self.getFileInfo()
@@ -58,8 +47,8 @@ class EdiskCz(SimpleHoster):
"action": action
})
- if not re.match(self.DLLINK_PATTERN, url):
- self.fail("Unexpected server response")
+ if not re.match(self.LINK_PATTERN, url):
+ self.fail(_("Unexpected server response"))
self.download(url)
diff --git a/module/plugins/hoster/EgoFilesCom.py b/module/plugins/hoster/EgoFilesCom.py
index 68a95b33a..9a2f50ed4 100644
--- a/module/plugins/hoster/EgoFilesCom.py
+++ b/module/plugins/hoster/EgoFilesCom.py
@@ -1,100 +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+) \|'
- FILE_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>'
- DIRECT_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 = ''
- 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.DIRECT_LINK_PATTERN, self.html)
- if not m:
- 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 not m:
- 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 65e9cb5c3..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"
- FILE_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 fa6342014..cc10abb37 100644
--- a/module/plugins/hoster/EuroshareEu.py
+++ b/module/plugins/hoster/EuroshareEu.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/>.
-
- @author: zoidberg
-"""
-
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>'
- FILE_OFFLINE_PATTERN = ur'<h2>S.bor sa nena.iel</h2>|Poşadovaná stránka neexistuje!'
+ 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/")
@@ -54,18 +43,19 @@ 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)
- found = re.search(self.FREE_URL_PATTERN, self.html)
- if found is None:
- self.parseError("Parse error (URL)")
- parsed_url = "http://euroshare.eu%s" % found.group(1)
+ m = re.search(self.FREE_URL_PATTERN, self.html)
+ if m is None:
+ 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 4dba81a8f..7609954d3 100644
--- a/module/plugins/hoster/ExtabitCom.py
+++ b/module/plugins/hoster/ExtabitCom.py
@@ -1,87 +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/>.
-
- @author: zoidberg
-"""
-
import re
-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, 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.5"
+
__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>'
- FILE_OFFLINE_PATTERN = r'>File not found<'
- TEMP_OFFLINE_PATTERN = r">(File is temporary unavailable|No download mirror)<"
+ 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/\w+/.*?)[\'"]'
- DOWNLOAD_LINK_PATTERN = r'[\'"](http://guest\d+\.extabit\.com/[a-z0-9]+/.*?)[\'"]'
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.wait(1 * 60 * 60, True)
+ 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:
+ get_data['challenge'], get_data['capture'] = recaptcha.challenge(captcha_key)
+ res = json_loads(self.load("http://extabit.com/file/%s/" % fileID, get=get_data))
+ if "ok" in res:
self.correctCaptcha()
break
else:
self.invalidCaptcha()
else:
- self.fail("Invalid captcha")
+ self.fail(_("Invalid captcha"))
else:
- self.parseError('Captcha')
+ self.error(_("Captcha"))
+
+ if not "href" in res:
+ self.error(_("Bad JSON response"))
+
+ self.html = self.load("http://extabit.com/file/%s%s" % (fileID, res['href']))
- if not "href" in response:
- self.parseError('JSON')
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ self.error(_("LINK_PATTERN not found"))
- self.html = self.load("http://extabit.com/file/%s%s" % (fileID, response['href']))
- m = re.search(self.DOWNLOAD_LINK_PATTERN, self.html)
- if not m:
- self.parseError('Download URL')
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 8eeabc17c..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 c7841a237..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/>.
-#
-# @author: zoidberg
-###############################################################################
-
-# 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")]
- FILE_INFO_PATTERN = r'<h1 class="dwp">(?P<N>[^<]+)</h1>\s*<div class="fileinfo">\s*Size\s*: (?P<S>\d+) (?P<U>\w+),'
- FILE_OFFLINE_PATTERN = '>(The file has been deleted|Requested page not found)'
+ URL_REPLACEMENTS = [("#.*", "")]
- FILE_URL_REPLACEMENTS = [("#.*", "")]
- SH_COOKIES = [(".fastshare.cz", "lang", "en")]
+ COOKIES = [("fastshare.cz", "lang", "en")]
- 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 = " credit for "
+ 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)'
- def handleFree(self):
- if "> 100% of FREE slots are full" in self.html:
- self.retry(120, 60, "No free slots")
+ LINK_FREE_PATTERN = r'action=(/free/.*?)>\s*<img src="([^"]*)"><br'
+ LINK_PREMIUM_PATTERN = r'(http://data\d+\.fastshare\.cz/download\.php\?id=\d+&)'
+
+ SLOT_ERROR = "> 100% of FREE slots are full"
+ CREDIT_ERROR = " credit for "
+
+
+ def checkErrors(self):
+ if self.SLOT_ERROR in self.html:
+ errmsg = self.info['error'] = _("No free slots")
+ self.retry(12, 60, errmsg)
+
+ if self.CREDIT_ERROR in self.html:
+ errmsg = self.info['error'] = _("Not enough traffic left")
+ self.logWarning(errmsg)
+ self.resetAccount()
+
+ self.info.pop('error', None)
- found = re.search(self.FREE_URL_PATTERN, self.html)
- if found:
- action, captcha_src = found.groups()
+
+ 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:
- found = re.search(self.PREMIUM_URL_PATTERN, self.html)
- if found:
- url = found.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 9e06972e2..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)
-
- found = re.search(r"Location\s*:\s*(.*)", self.header, re.I)
- if found and re.match(self.DIRECT_LINK_PATTERN, found.group(1)):
- location = found.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 34b4acd07..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__ = ""
+ __license__ = "GPLv3"
+ __authors__ = [("espes", None)]
getInfo = create_getInfo(FileApeCom)
diff --git a/module/plugins/hoster/FileParadoxIn.py b/module/plugins/hoster/FileParadoxIn.py
new file mode 100644
index 000000000..0b5b57e22
--- /dev/null
+++ b/module/plugins/hoster/FileParadoxIn.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
+
+
+class FileParadoxIn(XFSHoster):
+ __name__ = "FileParadoxIn"
+ __type__ = "hoster"
+ __version__ = "0.04"
+
+ __pattern__ = r'https?://(?:www\.)?fileparadox\.in/\w{12}'
+
+ __description__ = """FileParadox.in hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RazorWing", "muppetuk1@hotmail.com")]
+
+
+ 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 5a73fb9ef..e1bd8da71 100644
--- a/module/plugins/hoster/FileStoreTo.py
+++ b/module/plugins/hoster/FileStoreTo.py
@@ -1,47 +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/>.
-
- @author: Walter Purcaro
-"""
-
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")]
+
+
+ INFO_PATTERN = r'File: <span[^>]*>(?P<N>.+)</span><br />Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)'
+ OFFLINE_PATTERN = r'>Download-Datei wurde nicht gefunden<'
- FILE_INFO_PATTERN = r'File: <span[^>]*>(?P<N>.+)</span><br />Size: (?P<S>[\d,.]+) (?P<U>\w+)'
- FILE_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 56eedf33a..8b6804a68 100644
--- a/module/plugins/hoster/FilecloudIo.py
+++ b/module/plugins/hoster/FilecloudIo.py
@@ -1,119 +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/>.
-
- @author: zoidberg
-"""
-
import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError
+
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")]
+
+
+ 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'
- FILE_SIZE_PATTERN = r'{var __ab1 = (?P<S>\d+);}'
- FILE_NAME_PATTERN = r'id="aliasSpan">(?P<N>.*?)&nbsp;&nbsp;<'
- FILE_OFFLINE_PATTERN = r'l10n.(FILES__DOESNT_EXIST|REMOVED)'
- TEMP_OFFLINE_PATTERN = r'l10n.FILES__WARNING'
+ UKEY_PATTERN = r'\'ukey\'\s*:\'(\w+)'
+ AB1_PATTERN = r'if\( __ab1 == \'(\w+)\' \)'
+ ERROR_MSG_PATTERN = r'var __error_msg\s*=\s*l10n\.(.*?);'
+ RECAPTCHA_PATTERN = r'var __recaptcha_public\s*=\s*\'(.+?)\';'
+
+ LINK_PATTERN = r'"(http://s\d+\.filecloud\.io/%s/\d+/.*?)"'
- UKEY_PATTERN = r"'ukey'\s*:'(\w+)',"
- AB1_PATTERN = r"if\( __ab1 == '(\w+)' \)"
- ERROR_MSG_PATTERN = r"var __error_msg\s*=\s*l10n\.(.*?);"
- DOWNLOAD_LINK_PATTERN = r'"(http://s\d+.filecloud.io/%s/\d+/.*?)"'
- RECAPTCHA_KEY_PATTERN = r"var __recaptcha_public\s*=\s*'([^']+)';"
- RECAPTCHA_KEY = '6Lf5OdISAAAAAEZObLcx5Wlv4daMaASRov1ysDB1'
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.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()
- found = re.search(self.AB1_PATTERN, self.html)
- if not found:
- raise PluginParseError("__AB1")
- data["__ab1"] = found.group(1)
+ 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)
+ res = self.load(json_url, post=data)
+ self.logDebug(res)
+ res = json_loads(res)
- if "error" in response and response["error"]:
- self.fail(response)
+ if "error" in res and res['error']:
+ self.fail(res)
- self.logDebug(response)
- if response["captcha"]:
- recaptcha = ReCaptcha(self)
- found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html)
- captcha_key = found.group(1) if found else self.RECAPTCHA_KEY
- data["ctype"] = "recaptcha"
+ self.logDebug(res)
+ if res['captcha']:
+ data['ctype'] = "recaptcha"
- for _ in xrange(5):
- data["recaptcha_challenge"], data["recaptcha_response"] = recaptcha.challenge(captcha_key)
+ 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')
- found = re.search(self.DOWNLOAD_LINK_PATTERN % self.file_info['ID'], self.html)
- if not found:
- raise PluginParseError("Download URL")
- download_url = found.group(1)
- self.logDebug("Download URL: %s" % download_url)
-
- if "size" in self.file_info and self.file_info['size']:
- self.check_data = {"size": int(self.file_info['size'])}
+
+ m = re.search(self.LINK_PATTERN % self.info['pattern']['ID'], self.html)
+ if m is None:
+ self.error(_("LINK_PATTERN not found"))
+
+ if "size" in self.info and self.info['size']:
+ self.check_data = {"size": int(self.info['size'])}
+
+ download_url = m.group(1)
self.download(download_url)
else:
- self.fail("Unexpected server response")
+ 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 273a717b5..ada498a51 100644
--- a/module/plugins/hoster/FilefactoryCom.py
+++ b/module/plugins/hoster/FilefactoryCom.py
@@ -1,106 +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, create_getInfo
+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
+ yield (url, 0, 3, url)
+ 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.47"
+ __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")]
+
+
+ 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'
+
+ 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")]
- 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'
- DIRECT_LINK_PATTERN = r'<a href="(https?://[^"]+)"[^>]*><i[^>]*></i> Download with FileFactory Premium</a>'
- FILE_OFFLINE_PATTERN = r'<h2>File Removed</h2>'
- PREMIUM_ONLY_PATTERN = r'>Premium Account Required<'
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 not url:
- 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)
- found = re.search(self.DIRECT_LINK_PATTERN, html)
- if found:
- url = found.group(1)
+ 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)
-
-
-getInfo = create_getInfo(FilefactoryCom)
diff --git a/module/plugins/hoster/FilejungleCom.py b/module/plugins/hoster/FilejungleCom.py
index 910798bf6..8a8aee9e2 100644
--- a/module/plugins/hoster/FilejungleCom.py
+++ b/module/plugins/hoster/FilejungleCom.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 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/>.
-
- @author: zoidberg
-"""
-
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']
+ URLS = ["http://www.filejungle.com/f/", "http://www.filejungle.com/check_links.php",
+ "http://www.filejungle.com/checkReCaptcha.php"]
LINKCHECK_TR = r'<li>\s*(<div class="col1">.*?)</li>'
LINKCHECK_TD = r'<div class="(?:col )?col\d">(?:<[^>]*>|&nbsp;)*([^<]*)'
diff --git a/module/plugins/hoster/FileomCom.py b/module/plugins/hoster/FileomCom.py
index 9fda2353c..2b6fd34db 100644
--- a/module/plugins/hoster/FileomCom.py
+++ b/module/plugins/hoster/FileomCom.py
@@ -1,52 +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/>.
-#
-# @author: Walter Purcaro
-###############################################################################
-
-# 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 = \'(.+?)\';'
- DIRECT_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 01ac76850..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/>.
-
- @author: zoidberg
-
- 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.27"
+ __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"/>'
- #FILE_INFO_PATTERN = r'<h1>(?P<N>[^<]+)</h1>\s*<div class="ul">\s*<ul>\s*<li><span>Size:</span> (?P<S>[0-9.]+) (?P<U>[kKMG])i?B</li>'
- FILE_OFFLINE_PATTERN = r'class="error_msg_title"> Invalid or Deleted File. </div>|<div class="file_info file_info_deleted">'
- RECAPTCHA_KEY_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)
+ INFO_PATTERN = r'<input type="text" id="url" value=\'<a href[^>]*>(?P<N>[^>]+?) - (?P<S>[\d.,]+) (?P<U>[\w^_]+)</a>\' class="inp_text"/>'
+ OFFLINE_PATTERN = r'class="error_msg_title"> Invalid or Deleted File. </div>|<div class="file_info file_info_deleted">'
+
+ PREMIUM_ONLY_PATTERN = r'members only. Please upgrade to premium|a premium membership is required to download this file'
+ RECAPTCHA_PATTERN = r'Captcha.init\({\s*key:\s*\'(.+?)\''
+ FLP_TOKEN_PATTERN = r'set_store_options\({token: \'(.+?)\''
- found = re.search(self.FLP_TOKEN_PATTERN, self.html)
- if not found:
- self.parseError("Token")
- flp_token = found.group(1)
- found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html)
- if not found:
- self.parseError("Captcha key")
- captcha_key = found.group(1)
+ def handleFree(self):
+ m = re.search(self.FLP_TOKEN_PATTERN, self.html)
+ if m is None:
+ self.error(_("Token"))
+ flp_token = m.group(1)
+
+ m = re.search(self.RECAPTCHA_PATTERN, self.html)
+ if m is None:
+ self.error(_("Captcha key"))
+ captcha_key = m.group(1)
# Get wait time
get_dict = {'SID': self.req.cj.getCookie('SID'), 'JsHttpRequest': str(int(time() * 10000)) + '-xml'}
- post_dict = {'action': 'set_download', 'token': flp_token, 'code': 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
@@ -90,10 +74,10 @@ class FilepostCom(SimpleHoster):
for i in xrange(5):
get_dict['JsHttpRequest'] = str(int(time() * 10000)) + '-xml'
if i:
- post_dict["recaptcha_challenge_field"], post_dict["recaptcha_response_field"] = recaptcha.challenge(
+ post_dict['recaptcha_challenge_field'], post_dict['recaptcha_response_field'] = recaptcha.challenge(
captcha_key)
self.logDebug(u"RECAPTCHA: %s : %s : %s" % (
- captcha_key, post_dict["recaptcha_challenge_field"], post_dict["recaptcha_response_field"]))
+ captcha_key, post_dict['recaptcha_challenge_field'], post_dict['recaptcha_response_field']))
download_url = self.getJsonResponse(get_dict, post_dict, 'link')
if download_url:
@@ -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 d39666922..2a38ac470 100644
--- a/module/plugins/hoster/FilerNet.py
+++ b/module/plugins/hoster/FilerNet.py
@@ -1,119 +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>'
- FILE_OFFLINE_PATTERN = r'Nicht gefunden'
- RECAPTCHA_KEY = '6LcFctISAAAAAAgaeHgyqhNecGJJRnxV1m_vAz3V'
- DIRECT_LINK_PATTERN = r'href="([^"]+)">Get download</a>'
- def process(self, pyfile):
- if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()):
- self.handlePremium()
- else:
- self.handleFree()
+ 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 handleFree(self):
- self.req.setOption("timeout", 120)
- self.html = self.load(self.pyfile.url, decode=not self.SH_BROKEN_ENCODING, cookies=self.SH_COOKIES)
+ LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'href="([^"]+)">Get download</a>'
+
+ def checkErrors(self):
# Wait between downloads
m = re.search(r'musst du <span id="time">(\d+)</span> Sekunden warten', self.html)
if m:
- 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 = ''
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.DIRECT_LINK_PATTERN, html)
- if not m:
- 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 a0c67509f..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"
- FILE_OFFLINE_PATTERN = '<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 34998726d..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,22 +69,23 @@ 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"""
- file_url = re.search(self.url_pattern, self.html).group(0).split('<a href="')[1].split('" onclick="return Act')[
- 0]
- return file_url
+ 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"""
- file_name = re.search(self.url_pattern, self.html).group(0).split(', event)">')[1].split('</a>')[0]
- return file_name
+ 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
@@ -87,7 +93,7 @@ class FilesMailRu(Hoster):
# 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 4c678c1b1..52a071b52 100644
--- a/module/plugins/hoster/FileserveCom.py
+++ b/module/plugins/hoster/FileserveCom.py
@@ -1,34 +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.Hoster import Hoster
+
+from module.common.json_layer import json_loads
from module.network.RequestFactory import getURL
+from module.plugins.Hoster import Hoster
+from module.plugins.Plugin import chunks
from module.plugins.internal.CaptchaService import ReCaptcha
-from module.common.json_layer import json_loads
+from module.plugins.internal.SimpleHoster import secondsToMidnight
from module.utils import parseFileSize
-from module.plugins.Plugin import chunks
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:
@@ -44,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.51"
+ __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>'
+ URLS = ["http://www.fileserve.com/file/", "http://www.fileserve.com/link-checker.php",
+ "http://www.fileserve.com/checkReCaptcha.php"]
+ LINKCHECK_TR = r'<tr>\s*(<td>http://www\.fileserve\.com/file/.*?)</tr>'
LINKCHECK_TD = r'<td>(?:<[^>]*>|&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 = "Your download link has expired"
- DAILY_LIMIT_PATTERN = "Your daily download limit has been reached"
- NOT_LOGGED_IN_PATTERN = '<form (name="loginDialogBoxForm"|id="login_form")|<li><a href="/login.php">Login</a></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>'
- # 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:
@@ -83,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)
@@ -90,34 +84,34 @@ class FileserveCom(Hoster):
self.logDebug(action)
if "fail" in action:
- if action["fail"] == "timeLimit":
+ if action['fail'] == "timeLimit":
self.html = self.load(self.url, post={"checkDownload": "showError", "errorType": "timeLimit"},
decode=True)
self.doLongWait(re.search(self.LONG_WAIT_PATTERN, self.html))
- elif action["fail"] == "parallelDownload":
- self.logWarning(_("Parallel download error, now waiting 60s."))
- self.retry(wait_time=60, reason="parallelDownload")
+ elif action['fail'] == "parallelDownload":
+ self.logWarning(_("Parallel download error, now waiting 60s"))
+ self.retry(wait_time=60, reason=_("parallelDownload"))
else:
- self.fail("Download check returned %s" % action["fail"])
+ self.fail(_("Download check returned: %s") % action['fail'])
elif "success" in action:
- if action["success"] == "showCaptcha":
+ if action['success'] == "showCaptcha":
self.doCaptcha()
self.doTimmer()
- elif action["success"] == "showTimmer":
+ elif action['success'] == "showTimmer":
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"})
@@ -133,50 +127,51 @@ class FileserveCom(Hoster):
elif check == "wait":
self.doLongWait(self.lastCheck)
elif check == "limit":
- #download limited reached for today (not a exact time known)
- self.setWait(3 * 60 * 60, True) # wait 3 hours #TO-DO: resolve waittime using UnrestrictLi's secondsToMidnight
+ 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":
- found = re.search(r'"waitTime":(\d+)', response)
- if not found:
- self.fail("Cannot get wait time")
- wait_time = int(found.group(1))
+ m = re.search(r'"waitTime":(\d+)', res)
+ if m is None:
+ self.fail(_("Cannot get wait time"))
+ wait_time = int(m.group(1))
else:
- wait_time = int(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
@@ -184,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)
@@ -213,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 db2b1a998..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 = "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()
-
- self.link = self._getLink()
-
- if not self.link.startswith('http://'):
- self.link = "http://fileshare.in.ua" + self.link
-
- self.download(self.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 cd0902ab3..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.DIRECT_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
new file mode 100644
index 000000000..0e3a4e847
--- /dev/null
+++ b/module/plugins/hoster/FiredriveCom.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
+
+
+class FiredriveCom(DeadHoster):
+ __name__ = "FiredriveCom"
+ __type__ = "hoster"
+ __version__ = "0.05"
+
+ __pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/(mobile/)?(file|embed)/(?P<ID>\w+)'
+
+ __description__ = """Firedrive.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+getInfo = create_getInfo(FiredriveCom)
diff --git a/module/plugins/hoster/FlyFilesNet.py b/module/plugins/hoster/FlyFilesNet.py
index 3e0466a41..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):
- pyfile.name = re.search(self.FILE_NAME_PATTERN, pyfile.url).group(1)
- pyfile.name = urllib.unquote_plus(pyfile.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 9c7752fe1..0406df0c4 100644
--- a/module/plugins/hoster/FourSharedCom.py
+++ b/module/plugins/hoster/FourSharedCom.py
@@ -6,45 +6,51 @@ 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 = '<span title="Size: (?P<S>[0-9,.]+) (?P<U>[kKMG])i?B">'
- FILE_OFFLINE_PATTERN = '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_PATTERN = r'<meta name="title" content="(?P<N>.+?)"'
+ SIZE_PATTERN = r'<span title="Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)">'
+ OFFLINE_PATTERN = r'The file link that you requested is not valid\.|This file was deleted.'
+
+ NAME_REPLACEMENTS = [(r"&#(\d+).", lambda m: unichr(int(m.group(1))))]
+ SIZE_REPLACEMENTS = [(",", "")]
- DOWNLOAD_BUTTON_PATTERN = 'id="btnLink" href="(.*?)"'
- FID_PATTERN = 'name="d3fid" value="(.*?)"'
DOWNLOAD_URL_PATTERN = r'name="d3link" value="(.*?)"'
+ DOWNLOAD_BUTTON_PATTERN = r'id="btnLink" href="(.*?)"'
+ FID_PATTERN = r'name="d3fid" value="(.*?)"'
+
def handleFree(self):
if not self.account:
- self.fail("User not logged in")
+ self.fail(_("User not logged in"))
- found = re.search(self.DOWNLOAD_BUTTON_PATTERN, self.html)
- if found:
- link = found.group(1)
+ m = re.search(self.DOWNLOAD_BUTTON_PATTERN, self.html)
+ if m:
+ link = m.group(1)
else:
link = re.sub(r'/(download|get|file|document|photo|video|audio)/', r'/get/', self.pyfile.url)
self.html = self.load(link)
- found = re.search(self.DOWNLOAD_URL_PATTERN, self.html)
- if not found:
- self.parseError('Download link')
- link = found.group(1)
+ m = re.search(self.DOWNLOAD_URL_PATTERN, self.html)
+ if m is None:
+ self.error(_("Download link"))
+ link = m.group(1)
try:
- found = re.search(self.FID_PATTERN, self.html)
- response = self.load('http://www.4shared.com/web/d2/getFreeDownloadLimitInfo?fileId=%s' % found.group(1))
- self.logDebug(response)
+ m = re.search(self.FID_PATTERN, self.html)
+ 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 ad9abeb96..2238f07ef 100644
--- a/module/plugins/hoster/FreakshareCom.py
+++ b/module/plugins/hoster/FreakshareCom.py
@@ -1,23 +1,32 @@
# -*- coding: utf-8 -*-
import re
+
from module.plugins.Hoster import Hoster
from module.plugins.internal.CaptchaService import ReCaptcha
+from module.plugins.internal.SimpleHoster import secondsToMidnight
class FreakshareCom(Hoster):
- __name__ = "FreakshareCom"
- __type__ = "hoster"
+ __name__ = "FreakshareCom"
+ __type__ = "hoster"
+ __version__ = "0.40"
+
__pattern__ = r'http://(?:www\.)?freakshare\.(net|com)/files/\S*?/'
- __version__ = "0.38"
+
__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
@@ -41,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():
@@ -73,14 +81,16 @@ 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
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if not self.wantReconnect:
self.req_opts = self.get_download_options() # get the Post options for the Request
@@ -89,8 +99,9 @@ class FreakshareCom(Hoster):
else:
self.offline()
+
def get_file_name(self):
- if self.html is None:
+ if not self.html:
self.download_html()
if not self.wantReconnect:
file_name = re.search(r"<h1\sclass=\"box_heading\"\sstyle=\"text-align:center;\">([^ ]+)", self.html)
@@ -102,9 +113,10 @@ class FreakshareCom(Hoster):
else:
return self.pyfile.url
+
def get_file_size(self):
size = 0
- if self.html is None:
+ if not self.html:
self.download_html()
if not self.wantReconnect:
file_size_check = re.search(
@@ -116,30 +128,33 @@ class FreakshareCom(Hoster):
return size
+
def get_waiting_time(self):
- if self.html is None:
+ if not self.html:
self.download_html()
if "Your Traffic is used up for today" in self.html:
self.wantReconnect = True
- return 24 * 60 * 60
+ 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
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if re.search(r"This file does not exist!", self.html) is not None:
return False
else:
return True
+
def get_download_options(self):
re_envelope = re.search(r".*?value=\"Free\sDownload\".*?\n*?(.*?<.*?>\n*)*?\n*\s*?</form>",
self.html).group(0) # get the whole request
@@ -148,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_response_field"]) = re_captcha.challenge(challenge.group(1))
+ (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 d72b12a12..80d0b8515 100644
--- a/module/plugins/hoster/FreeWayMe.py
+++ b/module/plugins/hoster/FreeWayMe.py
@@ -1,49 +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"
- @author: Nicolas Giese
-"""
+ __pattern__ = r'https://(?:www\.)?free-way\.me/.+'
-from module.plugins.Hoster import Hoster
-
-
-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
+ self.multiDL = self.premium
+ self.chunkLimit = 1
- 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.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 eebb43b48..e56d1a299 100644
--- a/module/plugins/hoster/FreevideoCz.py
+++ b/module/plugins/hoster/FreevideoCz.py
@@ -1,68 +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 FreevideoCz(DeadHoster):
+ __name__ = "FreevideoCz"
+ __type__ = "hoster"
+ __version__ = "0.30"
- @author: zoidberg
-"""
+ __pattern__ = r'http://(?:www\.)?freevideo\.cz/vase-videa/.+'
-import re
-from module.plugins.Hoster import Hoster
-from module.network.RequestFactory import getURL
-
-
-def getInfo(urls):
- result = []
-
- for url in urls:
-
- html = getURL(url)
- if re.search(FreevideoCz.FILE_OFFLINE_PATTERN, html):
- # File offline
- result.append((url, 0, 1, url))
- else:
- result.append((url, 0, 2, url))
- yield result
-
-
-class FreevideoCz(Hoster):
- __name__ = "FreevideoCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?freevideo.cz/vase-videa/(.*)\.html'
- __version__ = "0.2"
__description__ = """Freevideo.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
- URL_PATTERN = r'clip: {\s*url: "([^"]+)"'
- FILE_OFFLINE_PATTERN = r'<h2 class="red-corner-full">Str.nka nebyla nalezena</h2>'
-
- def setup(self):
- self.multiDL = self.resumeDownload = True
-
- def process(self, pyfile):
-
- self.html = self.load(pyfile.url, decode=True)
-
- if re.search(self.FILE_OFFLINE_PATTERN, self.html):
- self.offline()
-
- found = re.search(self.URL_PATTERN, self.html)
- if found is None:
- self.fail("Parse error (URL)")
- download_url = found.group(1)
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- pyfile.name = re.match(self.__pattern__, pyfile.url).group(1) + ".mp4"
- self.download(download_url)
+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 f9a9b6c16..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)
-
- file_info = parseFileInfo(FshareVn, url, html)
+ html = getURL("http://www.fshare.vn/check_link.php",
+ post={'action': "check_link", 'arrlinks': url},
+ decode=True)
- yield file_info
+ yield parseFileInfo(FshareVn, url, html)
def doubleDecode(m):
@@ -24,21 +22,26 @@ 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"
-
- FILE_INFO_PATTERN = r'<p>(?P<N>[^<]+)<\\/p>[\\trn\s]*<p>(?P<S>[0-9,.]+)\s*(?P<U>[kKMG])i?B<\\/p>'
- FILE_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)]
- DOWNLOAD_URL_PATTERN = r'action="(http://download.*?)[#"]'
- VIP_URL_PATTERN = r'<form action="([^>]+)" method="get" name="frm_download">'
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ 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>'
+
+ NAME_REPLACEMENTS = [("(.*)", doubleDecode)]
+
+ LINK_PATTERN = r'action="(http://download.*?)[#"]'
WAIT_PATTERN = ur'Lượt tải xuống kế tiếp là:\s*(.*?)\s*<'
+
def process(self, pyfile):
self.html = self.load('http://www.fshare.vn/check_link.php', post={
"action": "check_link",
@@ -52,6 +55,7 @@ class FshareVn(SimpleHoster):
self.handleFree()
self.checkDownloadedFile()
+
def handleFree(self):
self.html = self.load(self.pyfile.url, decode=True)
@@ -61,49 +65,60 @@ 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)
self.checkErrors()
- found = re.search(r'var count = (\d+)', self.html)
- self.setWait(int(found.group(1)) if found else 30)
+ m = re.search(r'var count = (\d+)', self.html)
+ self.setWait(int(m.group(1)) if m else 30)
- found = re.search(self.DOWNLOAD_URL_PATTERN, self.html)
- if not found:
- self.parseError('FREE DL URL')
- self.url = found.group(1)
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ 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()
- found = re.search(self.WAIT_PATTERN, self.html)
- if found:
- self.logInfo("Wait until %s ICT" % found.group(1))
- wait_until = mktime(strptime(found.group(1), "%d/%m/%Y %H:%M"))
+ m = re.search(self.WAIT_PATTERN, self.html)
+ if m:
+ 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
@@ -112,4 +127,4 @@ class FshareVn(SimpleHoster):
})
if check == "not_found":
- self.fail("File not found on server")
+ self.fail(_("File not m on server"))
diff --git a/module/plugins/hoster/Ftp.py b/module/plugins/hoster/Ftp.py
index af9191a4d..c6ad68e49 100644
--- a/module/plugins/hoster/Ftp.py
+++ b/module/plugins/hoster/Ftp.py
@@ -1,43 +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/>.
-
- @author: jeix
- @author: mkaay
-"""
-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
@@ -53,38 +43,36 @@ class Ftp(Hoster):
if netloc in servers:
self.logDebug("Logging on to %s" % netloc)
- self.req.addAuth(self.account.accounts[netloc]["password"])
+ 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)
- found = re.search(r"Content-Length:\s*(\d+)", response)
- if found:
- pyfile.size = int(found.group(1))
+ 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]))
+ 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, 1)
- #self.core.files.addLinks(links, pyfile.package().id)
+ 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 0cd54d2ea..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 = "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
@@ -32,12 +39,13 @@ class GamefrontCom(Hoster):
pyfile.name = self._getName()
- self.link = self._getLink()
+ link = self._getLink()
+
+ if not link.startswith('http://'):
+ link = "http://www.gamefront.com/" + link
- if not self.link.startswith('http://'):
- self.link = "http://www.gamefront.com/" + self.link
+ self.download(link)
- self.download(self.link)
def _checkOnline(self):
if re.search(self.PATTERN_OFFLINE, self.html):
@@ -45,19 +53,19 @@ class GamefrontCom(Hoster):
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))
- self.link = re.search("<a href=\"(http://media[0-9]+\.gamefront.com/.*)\">click here</a>", self.html2)
-
- return self.link.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):
@@ -70,15 +78,13 @@ def getInfo(urls):
result.append((url, 0, 1, url))
else:
name = re.search(GamefrontCom.PATTERN_FILENAME, html)
-
if name is None:
result.append((url, 0, 1, url))
- continue
-
- name = name.group(1)
- size = re.search(GamefrontCom.PATTERN_FILESIZE, html)
- size = parseFileSize(size.group(1))
+ else:
+ name = name.group(1)
+ size = re.search(GamefrontCom.PATTERN_FILESIZE, html)
+ size = parseFileSize(size.group(1))
- result.append((name, size, 3, url))
+ result.append((name, size, 3, url))
yield result
diff --git a/module/plugins/hoster/GigapetaCom.py b/module/plugins/hoster/GigapetaCom.py
index 1282c996d..37af7f216 100644
--- a/module/plugins/hoster/GigapetaCom.py
+++ b/module/plugins/hoster/GigapetaCom.py
@@ -1,42 +1,31 @@
# -*- 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/>.
-
- @author: zoidberg
-"""
-
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")]
+
+
+ NAME_PATTERN = r'<img src=".*" alt="file" />-->\s*(?P<N>.*?)\s*</td>'
+ SIZE_PATTERN = r'<th>\s*Size\s*</th>\s*<td>\s*(?P<S>.*?)\s*</td>'
+ OFFLINE_PATTERN = r'<div id="page_error">'
+
+ COOKIES = [("gigapeta.com", "lang", "us")]
- SH_COOKIES = [("http://gigapeta.com", "lang", "us")]
- 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>'
- FILE_OFFLINE_PATTERN = r'<div id="page_error">'
def handleFree(self):
captcha_key = str(randint(1, 100000000))
@@ -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"})
- found = re.search(r"Location\s*:\s*(.*)", self.req.http.header, re.I)
- if found:
- download_url = found.group(1)
+ m = re.search(r'Location\s*:\s*(.+)', self.req.http.header, re.I)
+ if m:
+ 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 1f77b7fe0..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")]
+
+
+ NAME_PATTERN = r'You will be redirected to .*(?P<N>[^/ ]+) in'
+ OFFLINE_PATTERN = r'The file you requested was not found'
- FILE_NAME_PATTERN = r'<h3>Filename: (?P<N>.+)</h3>'
- FILE_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 91e51e314..4b44cc335 100644
--- a/module/plugins/hoster/HellshareCz.py
+++ b/module/plugins/hoster/HellshareCz.py
@@ -1,59 +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/>.
-
- @author: zoidberg
-"""
-
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>'
- FILE_OFFLINE_PATTERN = r'<h1>File not found.</h1>'
+ 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)
- found = re.search(self.SHOW_WINDOW_PATTERN, self.html)
- if not found:
- self.parseError('SHOW WINDOW')
- self.url = "http://www.hellshare.com" + found.group(1)
- self.logDebug("DOWNLOAD URL: " + self.url)
+ m = re.search(self.SHOW_WINDOW_PATTERN, self.html)
+ if m is None:
+ 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 e4ddce514..2b9b76b8a 100644
--- a/module/plugins/hoster/HellspyCz.py
+++ b/module/plugins/hoster/HellspyCz.py
@@ -1,33 +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/>.
-
- @author: zoidberg
-"""
-
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 5b0adaa97..b4f225c4b 100644
--- a/module/plugins/hoster/IFileWs.py
+++ b/module/plugins/hoster/IFileWs.py
@@ -1,22 +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 = '<h1\s+style="display:inline;">(?P<N>[^<]+)</h1>\s+\[(?P<S>[^]]+)\]'
- FILE_OFFLINE_PATTERN = 'File Not Found|The file was removed by administrator'
- LONG_WAIT_PATTERN = "(?P<M>\d(?=\s+minutes)).*(?P<S>\d+(?=\s+seconds))"
+ __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 82d760d01..921b64207 100644
--- a/module/plugins/hoster/IcyFilesCom.py
+++ b/module/plugins/hoster/IcyFilesCom.py
@@ -1,33 +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/>.
-
- @author: godofdream
-"""
-
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 6c754624b..2dae4cd80 100644
--- a/module/plugins/hoster/IfileIt.py
+++ b/module/plugins/hoster/IfileIt.py
@@ -1,77 +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/>.
-
- @author: zoidberg
-"""
-
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"
-
- #EVAL_PATTERN = r'(eval\(function\(p,a,c,k,e,d\).*)'
- #DEC_PATTERN = r"requestBtn_clickEvent[^}]*url:\s*([^,]+)"
- DOWNLOAD_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>'
- FILE_OFFLINE_PATTERN = r'<span style="cursor: default;[^>]*>\s*&nbsp;\s*<strong>\s*</strong>\s*</span>'
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ LINK_PATTERN = r'</span> If it doesn\'t, <a target="_blank" href="([^"]+)">'
+ 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"
+ 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 7c5fede72..255f10f45 100644
--- a/module/plugins/hoster/IfolderRu.py
+++ b/module/plugins/hoster/IfolderRu.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/>.
-
- @author: zoidberg
-"""
-
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"
-
- 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)>'
- FILE_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'"
- DOWNLOAD_LINK_PATTERN = r'<a id="download_file_href" href="([^"]+)"'
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ SIZE_REPLACEMENTS = [(u'Кб', 'KB'), (u'Мб', 'MB'), (u'Гб', 'GB')]
+ NAME_PATTERN = ur'(?:<div><span>)?НазваМОе:(?:</span>)? <b>(?P<N>[^<]+)</b><(?:/div|br)>'
+ SIZE_PATTERN = ur'(?:<div><span>)?РазЌер:(?:</span>)? <b>(?P<S>[^<]+)</b><(?:/div|br)>'
+ OFFLINE_PATTERN = ur'<p>Ѐайл МПЌер <b>[^<]*</b> (Ме МайЎеМ|уЎалеМ) !!!</p>'
+
+ SESSION_ID_PATTERN = r'<a href=(http://ints\.(?:rusfolder\.com|ifolder\.ru)/ints/sponsor/\?bi=\d*&session=([^&]+)&u=[^>]+)>'
+ INTS_SESSION_PATTERN = r'\(\'ints_session\'\);\s*if\(tag\)\{tag\.value = "([^"]+)";\}'
+ HIDDEN_INPUT_PATTERN = r'var v = .*?name=\'(.+?)\' value=\'1\''
+ LINK_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)
@@ -62,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)
@@ -77,11 +66,10 @@ class IfolderRu(SimpleHoster):
else:
break
else:
- self.fail("Invalid captcha")
+ self.fail(_("Invalid captcha"))
- download_url = re.search(self.DOWNLOAD_LINK_PATTERN, self.html).group(1)
+ 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 cdeffff34..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")]
+
+
+ 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=(.+)">'
- FILE_INFO_PATTERN = '<TR><TD>(?P<N>[^<]+?)\s*<small>\((?P<S>[\d.]+)\s*(?P<U>[KMG][bB])\)</small></TD></TR>'
- FILE_OFFLINE_PATTERN = 'Not Found or Deleted / Disabled due to inactivity or DMCA'
- DIRECT_LINK_PATTERN = '<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.DIRECT_LINK_PATTERN, html).group(1)
- self.logDebug("Download " + url)
+ url = re.search(self.LINK_PATTERN, html).group(1)
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 a7f1efdb8..000000000
--- a/module/plugins/hoster/Keep2shareCC.py
+++ /dev/null
@@ -1,120 +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>'
- FILE_OFFLINE_PATTERN = r'File not found or deleted|Sorry, this file is blocked or deleted|Error 404'
-
- DIRECT_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.DIRECT_LINK_PATTERN, self.html)
- if not m:
- 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 426a757b3..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}'
- FILE_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 58532fd28..a7b11047f 100644
--- a/module/plugins/hoster/LetitbitNet.py
+++ b/module/plugins/hoster/LetitbitNet.py
@@ -1,40 +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/>.
-
- @author: zoidberg
-"""
-
+#
# 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.plugins.internal.SimpleHoster import SimpleHoster
+from urllib import urlencode, urlopen
+from urlparse import urljoin
+
from module.common.json_layer import json_loads, json_dumps
from module.plugins.internal.CaptchaService import ReCaptcha
+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()
+ json_data = ["yw7XQy2v9", ["download/info", {"link": url}]]
+ 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)
@@ -49,25 +34,27 @@ def getInfo(urls):
class LetitbitNet(SimpleHoster):
- __name__ = "LetitbitNet"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?(letitbit|shareflare).net/download/.*'
- __version__ = "0.23"
+ __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")]
- CHECK_URL_PATTERN = r"ajax_check_url\s*=\s*'((http://[^/]+)[^']+)';"
- SECONDS_PATTERN = r"seconds\s*=\s*(\d+);"
- CAPTCHA_CONTROL_FIELD = r"recaptcha_control_field\s=\s'(?P<value>[^']+)'"
- DOMAIN = "http://letitbit.net"
- FILE_URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "letitbit.net")]
- RECAPTCHA_KEY = "6Lc9zdMSAAAAAF-7s2wuQ-036pLRbM0p8dDaQdAM"
+ URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "letitbit.net")]
+
+ SECONDS_PATTERN = r'seconds\s*=\s*(\d+);'
+ CAPTCHA_CONTROL_FIELD = r'recaptcha_control_field\s=\s\'(.+?)\''
+
def setup(self):
self.resumeDownload = True
- #TODO confirm that resume works
+
def getFileInfo(self):
api_rep = api_download_info(self.pyfile.url)
@@ -78,92 +65,77 @@ 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"))
+
self.pyfile.size = float(inputs['sssize'])
self.logDebug(action, inputs)
inputs['desc'] = ""
- self.html = self.load(self.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()
- # found = re.search(self.SECONDS_PATTERN, self.html)
- # seconds = int(found.group(1)) if found else 60
- # self.wait(seconds+1)
- # except Exception, e:
- # self.logError(e)
- # self.parseError("page 3 / js")
-
- found = re.search(self.SECONDS_PATTERN, self.html)
- seconds = int(found.group(1)) if found else 60
+ self.html = self.load(urljoin("http://letitbit.net/", action), post=inputs, cookies=True)
+
+ m = re.search(self.SECONDS_PATTERN, self.html)
+ seconds = int(m.group(1)) if m else 60
self.logDebug("Seconds found", seconds)
- found = re.search(self.CAPTCHA_CONTROL_FIELD, self.html)
- recaptcha_control_field = found.group(1)
+ 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" % self.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' % self.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.logInfo("Daily limit reached, waiting 24 hours")
- self.wait(24 * 60 * 60)
- if response == "error_wrong_captcha":
- self.logInfo("Wrong Captcha")
+ if res == "error_free_download_blocked":
+ self.logWarning(_("Daily limit reached"))
+ self.wait(secondsToMidnight(gmt=2), True)
+ if res == "error_wrong_captcha":
self.invalidCaptcha()
self.retry()
- elif 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
- premium_key = self.account.getAccountData(self.user)["password"]
+ premium_key = self.account.getAccountData(self.user)['password']
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 2ed7744d7..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 e52346274..0a5b26410 100644
--- a/module/plugins/hoster/LoadTo.py
+++ b/module/plugins/hoster/LoadTo.py
@@ -1,90 +1,75 @@
# -*- 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
import re
+from module.plugins.internal.CaptchaService import SolveMedia
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-from module.plugins.internal.CaptchaService import ReCaptcha
class LoadTo(SimpleHoster):
- __name__ = "LoadTo"
- __type__ = "hoster"
+ __name__ = "LoadTo"
+ __type__ = "hoster"
+ __version__ = "0.18"
+
__pattern__ = r'http://(?:www\.)?load\.to/\w+'
- __version__ = "0.13"
- __description__ = """Load.to hoster plugin"""
- __author_name__ = ("halfman", "stickell")
- __author_mail__ = ("Pulpan3@gmail.com", "l.stickell@yahoo.it")
-
- FILE_INFO_PATTERN = r'<a [^>]+>(?P<N>.+)</a></h3>\s*Size: (?P<S>\d+) (?P<U>[kKmMgG]?i?[bB])'
- URL_PATTERN = r'<form method="post" action="(.+?)"'
- FILE_OFFLINE_PATTERN = r'Can\'t find file. Please check URL.'
+
+ __description__ = """ Load.to hoster plugin """
+ __license__ = "GPLv3"
+ __authors__ = [("halfman", "Pulpan3@gmail.com"),
+ ("stickell", "l.stickell@yahoo.it")]
+
+
+ NAME_PATTERN = r'<h1>(?P<N>.+)</h1>'
+ SIZE_PATTERN = r'Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)'
+ OFFLINE_PATTERN = r'>Can\'t find file'
+
+ LINK_PATTERN = r'<form method="post" action="(.+?)"'
WAIT_PATTERN = r'type="submit" value="Download \((\d+)\)"'
- RECAPTCHA_PATTERN = r'http://www.google.com/recaptcha/api/challenge'
- RECAPTCHA_KEY = "6Lc34eISAAAAAKNbPVyxBgNriTjPRmF-FA1oxApG"
+
+ URL_REPLACEMENTS = [(r'(\w)$', r'\1/')]
+
def setup(self):
self.multiDL = True
self.chunkLimit = 1
- def process(self, pyfile):
- self.html = self.load(pyfile.url, decode=True)
- self.getFileInfo()
-
- # Check if File is online
- if re.search(self.FILE_OFFLINE_PATTERN, self.html):
- self.offline()
+ def handleFree(self):
# Search for Download URL
- m = re.search(self.URL_PATTERN, self.html)
- if not m:
- self.parseError('Unable to detect download URL')
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ 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)))
- # Check if reCaptcha is present
- m = re.search(self.RECAPTCHA_PATTERN, self.html)
- if not m: # No captcha found
+ # Load.to is using solvemedia captchas since ~july 2014:
+ solvemedia = SolveMedia(self)
+ captcha_key = solvemedia.detect_key()
+
+ if captcha_key is None:
self.download(download_url)
else:
- recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
- if not response == '0':
- break
- else:
- self.fail("No valid captcha solution received")
-
- self.download(download_url,
- post={'recaptcha_challenge_field': challenge, 'recaptcha_response_field': response})
-
- # Verifiy reCaptcha by checking content of file for html 404-error
- 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
new file mode 100644
index 000000000..475cdacaa
--- /dev/null
+++ b/module/plugins/hoster/LomafileCom.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
+
+
+class LomafileCom(DeadHoster):
+ __name__ = "LomafileCom"
+ __type__ = "hoster"
+ __version__ = "0.52"
+
+ __pattern__ = r'http://lomafile\.com/\w{12}'
+
+ __description__ = """Lomafile.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com"),
+ ("guidobelix", "guidobelix@hotmail.it")]
+
+
+getInfo = create_getInfo(LomafileCom)
diff --git a/module/plugins/hoster/LuckyShareNet.py b/module/plugins/hoster/LuckyShareNet.py
index 75520a6cf..2c33b57e7 100644
--- a/module/plugins/hoster/LuckyShareNet.py
+++ b/module/plugins/hoster/LuckyShareNet.py
@@ -1,70 +1,72 @@
# -*- 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")]
+
+
+ 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'
- 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>"
- FILE_OFFLINE_PATTERN = 'There is no such file available'
- RECAPTCHA_KEY = '6LdivsgSAAAAANWh-d7rPE1mus4yVWuSQIJKIYNw'
def parseJson(self, rep):
if 'AJAX Error' in rep:
html = self.load(self.pyfile.url, decode=True)
m = re.search(r"waitingtime = (\d+);", html)
if m:
- 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 52e38aada..782d78ce1 100644
--- a/module/plugins/hoster/MediafireCom.py
+++ b/module/plugins/hoster/MediafireCom.py
@@ -1,25 +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/>.
-
- @author: zoidberg
-"""
-
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
@@ -29,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")
-
- DOWNLOAD_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="([^"]+)"/>'
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it")]
+
+
+ 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"'
- FILE_NAME_PATTERN = r'<META NAME="description" CONTENT="(?P<N>[^"]+)"/>'
- FILE_INFO_PATTERN = r"oFileSharePopup\.ald\('(?P<ID>[^']*)','(?P<N>[^']*)','(?P<S>[^']*)','','(?P<sha256>[^']*)'\)"
- FILE_OFFLINE_PATTERN = r'class="error_msg_title"> Invalid or Deleted File. </div>'
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()
@@ -103,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"))
- found = re.search(r'kNO = "(http://.*?)";', self.html)
- if not found:
- self.parseError("Download URL")
- download_url = found.group(1)
- self.logDebug("DOWNLOAD LINK:", download_url)
+ m = re.search(r'kNO = r"(http://.*?)";', self.html)
+ if m is None:
+ self.error(_("No download URL"))
+ download_url = m.group(1)
self.download(download_url)
+
def checkCaptcha(self):
- for _ in xrange(5):
- found = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if found:
- captcha_key = found.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/MegaCoNz.py b/module/plugins/hoster/MegaCoNz.py
new file mode 100644
index 000000000..fc6724dc7
--- /dev/null
+++ b/module/plugins/hoster/MegaCoNz.py
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+
+import random
+import re
+
+from array import array
+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
+
+############################ 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!-]+)'
+
+ __description__ = """Mega.co.nz hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "ranan@pyload.org")]
+
+ 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)
+
+ 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):
+ cbc = AES.new(self.getCipherKey(key), AES.MODE_CBC, "\0" * 16)
+ attr = cbc.decrypt(self.b64_decode(data))
+ self.logDebug("Decrypted Attr: " + attr)
+ if not attr.startswith("MEGA"):
+ self.fail(_("Decryption failed"))
+
+ # Data is padded, 0-bytes must be stripped
+ return json_loads(re.search(r'{.+?}', attr).group(0))
+
+
+ def decryptFile(self, key):
+ """ Decrypts the file at lastDownload` """
+
+ # upper 64 bit of counter start
+ n = key[16:24]
+
+ # convert counter to long and shift bytes
+ ctr = Counter.new(128, initial_value=long(n.encode("hex"), 16) << 64)
+ cipher = AES.new(self.getCipherKey(key), AES.MODE_CTR, counter=ctr)
+
+ self.pyfile.setStatus("decrypting")
+
+ file_crypted = self.lastDownload
+ file_decrypted = file_crypted.rsplit(self.FILE_SUFFIX)[0]
+
+ try:
+ f = open(file_crypted, "rb")
+ df = open(file_decrypted, "wb")
+ except IOError, e:
+ self.fail(str(e))
+
+ # TODO: calculate CBC-MAC for checksum
+
+ size = 2 ** 15 # buffer size, 32k
+ while True:
+ buf = f.read(size)
+ if not buf:
+ break
+
+ df.write(cipher.decrypt(buf))
+
+ f.close()
+ df.close()
+ remove(file_crypted)
+
+ self.lastDownload = file_decrypted
+
+
+ def process(self, pyfile):
+ key = None
+
+ # match is guaranteed because plugin was chosen to handle url
+ node = re.match(self.__pattern__, pyfile.url).group('ID')
+ if "!" in node:
+ node, key = node.split("!", 1)
+
+ self.logDebug("ID: %s | Key: %s" % (node, key))
+
+ if not key:
+ self.fail(_("No file key provided in the URL"))
+
+ # g is for requesting a download url
+ # this is similar to the calls in the mega js app, documentation is very bad
+ dl = self.callApi(a="g", g=1, p=node, ssl=1)[0]
+
+ if "e" in dl:
+ e = dl['e']
+ # ETEMPUNAVAIL (-18): Resource temporarily not available, please try again later
+ if e == -18:
+ self.retry()
+ else:
+ self.fail(_("Error code:") + e)
+
+ # TODO: map other error codes, e.g
+ # EACCESS (-11): Access violation (e.g., trying to write to a read-only share)
+
+ key = self.b64_decode(key)
+ attr = self.decryptAttr(dl['at'], key)
+
+ 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)
+
+ # Everything is finished and final name can be set
+ pyfile.name = attr['n']
diff --git a/module/plugins/hoster/MegaDebridEu.py b/module/plugins/hoster/MegaDebridEu.py
index 46eb0eb11..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.3"
- __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(_("Impossible 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):
"""
@@ -64,15 +49,16 @@ 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)
+ get={'action': 'connectUser', 'login': user, 'password': data['password']})
+ 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,13 +66,14 @@ 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(_("Impossible to debrid %s") % linkToDebrid)
+ self.exitOnFail("Unable to debrid %s" % linkToDebrid)
+
def exitOnFail(self, msg):
"""
@@ -94,7 +81,10 @@ class MegaDebridEu(Hoster):
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 43601bdb1..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}'
- FILE_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/MegaNz.py b/module/plugins/hoster/MegaNz.py
deleted file mode 100644
index a55220bc2..000000000
--- a/module/plugins/hoster/MegaNz.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-import random
-from array import array
-from os import remove
-from base64 import standard_b64decode
-
-from Crypto.Cipher import AES
-from Crypto.Util import Counter
-
-from module.common.json_layer import json_loads, json_dumps
-from module.plugins.Hoster import Hoster
-
-#def getInfo(urls):
-# pass
-
-
-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", )
-
- API_URL = "https://g.api.mega.co.nz/cs?id=%d"
- 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)
-
- 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)
- if not attr.startswith("MEGA"):
- self.fail(_("Decryption failed"))
-
- # Data is padded, 0-bytes must be stripped
- return json_loads(attr.replace("MEGA", "").rstrip("\0").strip())
-
- def decryptFile(self, key):
- """ Decrypts the file at lastDownload` """
-
- # upper 64 bit of counter start
- n = key[16:24]
-
- # convert counter to long and shift bytes
- ctr = Counter.new(128, initial_value=long(n.encode("hex"), 16) << 64)
- cipher = AES.new(self.getCipherKey(key), AES.MODE_CTR, counter=ctr)
-
- self.pyfile.setStatus("decrypting")
-
- file_crypted = self.lastDownload
- file_decrypted = file_crypted.rsplit(self.FILE_SUFFIX)[0]
- f = open(file_crypted, "rb")
- df = open(file_decrypted, "wb")
-
- # TODO: calculate CBC-MAC for checksum
-
- size = 2 ** 15 # buffer size, 32k
- while True:
- buf = f.read(size)
- if not buf:
- break
-
- df.write(cipher.decrypt(buf))
-
- f.close()
- df.close()
- remove(file_crypted)
-
- self.lastDownload = file_decrypted
-
- 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)
- if "!" in node:
- node, key = node.split("!")
-
- self.logDebug("File id: %s | Key: %s" % (node, key))
-
- if not key:
- self.fail(_("No file key provided in the URL"))
-
- # g is for requesting a download url
- # this is similar to the calls in the mega js app, documentation is very bad
- dl = self.callApi(a="g", g=1, p=node, ssl=1)[0]
-
- if "e" in dl:
- e = dl["e"]
- # ETEMPUNAVAIL (-18): Resource temporarily not available, please try again later
- if e == -18:
- self.retry()
- else:
- self.fail(_("Error code:") + e)
-
- # TODO: map other error codes, e.g
- # EACCESS (-11): Access violation (e.g., trying to write to a read-only share)
-
- key = self.b64_decode(key)
- attr = self.decryptAttr(dl["at"], key)
-
- pyfile.name = attr["n"] + self.FILE_SUFFIX
-
- self.download(dl["g"])
- self.decryptFile(key)
-
- # Everything is finished and final name can be set
- pyfile.name = attr["n"]
diff --git a/module/plugins/hoster/MegaRapidCz.py b/module/plugins/hoster/MegaRapidCz.py
new file mode 100644
index 000000000..37732ade6
--- /dev/null
+++ b/module/plugins/hoster/MegaRapidCz.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from pycurl import HTTPHEADER
+
+from module.network.RequestFactory import getRequest
+from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo
+
+
+def getInfo(urls):
+ h = getRequest()
+ h.c.setopt(HTTPHEADER,
+ ["Accept: text/html",
+ "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0"])
+
+ for url in urls:
+ html = h.load(url, decode=True)
+ yield parseFileInfo(MegaRapidCz, url, html)
+
+
+class MegaRapidCz(SimpleHoster):
+ __name__ = "MegaRapidCz"
+ __type__ = "hoster"
+ __version__ = "0.55"
+
+ __pattern__ = r'http://(?:www\.)?(share|mega)rapid\.cz/soubor/\d+/.+'
+
+ __description__ = """MegaRapid.cz hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("MikyWoW", "mikywow@seznam.cz"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ NAME_PATTERN = r'<h1[^>]*><span[^>]*>(?:<a[^>]*>)?(?P<N>[^<]+)'
+ SIZE_PATTERN = r'<td class="i">Velikost:</td>\s*<td class="h"><strong>\s*(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong></td>'
+ OFFLINE_PATTERN = ur'Nastala chyba 404|Soubor byl smazán'
+
+ CHECK_TRAFFIC = True
+
+ LINK_PATTERN = r'<a href="([^"]+)" title="Stahnout">([^<]+)</a>'
+ ERR_LOGIN_PATTERN = ur'<div class="error_div"><strong>Stahování je přístupné pouze přihlášenÃœm uÅŸivatelům'
+ ERR_CREDIT_PATTERN = ur'<div class="error_div"><strong>Stahování zdarma je moÅŸné jen přes náš'
+
+
+ def setup(self):
+ self.chunkLimit = 1
+
+
+ def handlePremium(self):
+ try:
+ self.html = self.load(self.pyfile.url, decode=True)
+ except BadHeader, e:
+ self.account.relogin(self.user)
+ self.retry(wait_time=60, reason=str(e))
+
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m:
+ link = m.group(1)
+ self.logDebug("Premium link: %s" % link)
+ self.download(link, disposition=True)
+ else:
+ if re.search(self.ERR_LOGIN_PATTERN, self.html):
+ self.relogin(self.user)
+ self.retry(wait_time=60, reason=_("User login failed"))
+ elif re.search(self.ERR_CREDIT_PATTERN, self.html):
+ self.fail(_("Not enough credit left"))
+ else:
+ self.fail(_("Download link not found"))
diff --git a/module/plugins/hoster/MegacrypterCom.py b/module/plugins/hoster/MegacrypterCom.py
index 8b72606ce..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
@@ -36,15 +42,15 @@ class MegacrypterCom(MegaNz):
dl = self.callApi(link=node, m="dl")
# TODO: map error codes, implement password protection
- # if info["pass"] == true:
- # crypted_file_key, md5_file_key = info["key"].split("#")
+ # if info['pass'] is True:
+ # crypted_file_key, md5_file_key = info['key'].split("#")
- key = self.b64_decode(info["key"])
+ key = self.b64_decode(info['key'])
- pyfile.name = info["name"] + self.FILE_SUFFIX
+ pyfile.name = info['name'] + self.FILE_SUFFIX
- self.download(dl["url"])
+ self.download(dl['url'])
self.decryptFile(key)
# Everything is finished and final name can be set
- pyfile.name = info["name"]
+ pyfile.name = info['name']
diff --git a/module/plugins/hoster/MegareleaseOrg.py b/module/plugins/hoster/MegareleaseOrg.py
index cb8c7aa01..60796c1ee 100644
--- a/module/plugins/hoster/MegareleaseOrg.py
+++ b/module/plugins/hoster/MegareleaseOrg.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 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"
+
+ __pattern__ = r'https?://(?:www\.)?megarelease\.org/\w{12}'
- HOSTER_NAME = "megarelease.org"
+ __description__ = """Megarelease.org hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("derek3x", "derek3x@vmail.me"),
+ ("stickell", "l.stickell@yahoo.it")]
- FILE_INFO_PATTERN = r'<font color="red">%s/(?P<N>.+)</font> \((?P<S>[^)]+)\)</font>' % __pattern__
getInfo = create_getInfo(MegareleaseOrg)
diff --git a/module/plugins/hoster/MegasharesCom.py b/module/plugins/hoster/MegasharesCom.py
index b73b4943c..9d8441c6f 100644
--- a/module/plugins/hoster/MegasharesCom.py
+++ b/module/plugins/hoster/MegasharesCom.py
@@ -1,113 +1,111 @@
# -*- 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/>.
-
- @author: zoidberg
-"""
-
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"
-
- FILE_NAME_PATTERN = '<h1 class="black xxl"[^>]*title="(?P<N>[^"]+)">'
- FILE_SIZE_PATTERN = '<strong><span class="black">Filesize:</span></strong> (?P<S>[0-9.]+) (?P<U>[kKMG])i?B<br />'
- DOWNLOAD_URL_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>'
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ NAME_PATTERN = r'<h1 class="black xxl"[^>]*title="(?P<N>[^"]+)">'
+ SIZE_PATTERN = r'<strong><span class="black">Filesize:</span></strong> (?P<S>[\d.,]+) (?P<U>[\w^_]+)'
+ OFFLINE_PATTERN = r'<dd class="red">(Invalid Link Request|Link has been deleted|Invalid link)'
+
+ LINK_PATTERN = r'<div id="show_download_button_%d"[^>]*>\s*<a href="([^"]+)">'
+
+ PASSPORT_LEFT_PATTERN = r'Your Download Passport is: <[^>]*>(\w+).*?You have.*?<[^>]*>.*?([\d.]+) (\w+)'
+ PASSPORT_RENEW_PATTERN = r'(\d+):<strong>(\d+)</strong>:<strong>(\d+)</strong>'
REACTIVATE_NUM_PATTERN = r'<input[^>]*id="random_num" value="(\d+)" />'
REACTIVATE_PASSPORT_PATTERN = r'<input[^>]*id="passport_num" value="(\w+)" />'
REQUEST_URI_PATTERN = r'var request_uri = "([^"]+)";'
NO_SLOTS_PATTERN = r'<dd class="red">All download slots for this link are currently filled'
- FILE_OFFLINE_PATTERN = r'<dd class="red">(Invalid Link Request|Link has been deleted)'
+
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
- found = re.search(self.REACTIVATE_PASSPORT_PATTERN, self.html)
- if found:
- passport_num = found.group(1)
+ 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
- found = re.search(self.PASSPORT_LEFT_PATTERN, self.html)
- if not found:
- self.fail('Passport not found')
- self.logInfo("Download passport: %s" % found.group(1))
- data_left = float(found.group(2)) * 1024 ** {'KB': 1, 'MB': 2, 'GB': 3}[found.group(3)]
- self.logInfo("Data left: %s %s (%d MB needed)" % (found.group(2), found.group(3), self.pyfile.size / 1048576))
+ m = re.search(self.PASSPORT_LEFT_PATTERN, self.html, re.M | re.S)
+ if m is None:
+ self.fail(_("Passport not found"))
+
+ self.logInfo(_("Download passport: %s") % m.group(1))
+ data_left = float(m.group(2)) * 1024 ** {'B': 0, 'KB': 1, 'MB': 2, 'GB': 3}[m.group(3)]
+ self.logInfo(_("Data left: %s %s (%d MB needed)") % (m.group(2), m.group(3), self.pyfile.size / 1048576))
if not data_left:
- found = re.search(self.PASSPORT_RENEW_PATTERN, self.html)
- renew = found.group(1) + found.group(2) + found.group(3) * 60 * 60 if found 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;
- found = re.search(self.DOWNLOAD_URL_PATTERN % (1 if premium else 2), self.html)
- msg = '%s download URL' % ('Premium' if premium else 'Free')
- if not found:
- self.parseError(msg)
+ m = re.search(self.LINK_PATTERN % (1 if premium else 2), self.html)
+ msg = _('%s download URL' % ('Premium' if premium else 'Free'))
+ if m is None:
+ self.error(msg)
- download_url = found.group(1)
+ download_url = m.group(1)
self.logDebug("%s: %s" % (msg, download_url))
self.download(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 2dedcf13d..9bb63701c 100644
--- a/module/plugins/hoster/MovReelCom.py
+++ b/module/plugins/hoster/MovReelCom.py
@@ -1,27 +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(XFileSharingPro):
- __name__ = "MovReelCom"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?movreel.com/.*'
- __version__ = "1.20"
+class MovReelCom(XFSHoster):
+ __name__ = "MovReelCom"
+ __type__ = "hoster"
+ __version__ = "1.24"
+
+ __pattern__ = r'http://(?:www\.)?movreel\.com/\w{12}'
+
__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_NAME_PATTERN = r'<b>Filename:</b>(?P<N>.*?)<br>'
- #FILE_SIZE_PATTERN = r'<b>Size:</b>(?P<S>.*?)<br>'
- FILE_INFO_PATTERN = r'<h3>(?P<N>.+?) <small><sup>(?P<S>[\d.]+) (?P<U>..)</sup> </small></h3>'
- FILE_OFFLINE_PATTERN = r'<b>File Not Found</b><br><br>'
- DIRECT_LINK_PATTERN = r'<a href="(http://[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/.*)">Download Link</a>'
- #OVR_DOWNLOAD_LINK_PATTERN = "var file_link = '(.*)';"
+ 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 e38bd048f..adbae2da4 100644
--- a/module/plugins/hoster/MultishareCz.py
+++ b/module/plugins/hoster/MultishareCz.py
@@ -1,84 +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/>.
-
- @author: zoidberg
-"""
-
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"
-
- FILE_INFO_PATTERN = ur'(?:<li>Název|Soubor): <strong>(?P<N>[^<]+)</strong><(?:/li><li|br)>Velikost: <strong>(?P<S>[^<]+)</strong>'
- FILE_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()
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ SIZE_REPLACEMENTS = [('&nbsp;', '')]
+
+ MULTI_HOSTER = True
+
+ INFO_PATTERN = ur'(?:<li>Název|Soubor): <strong>(?P<N>[^<]+)</strong><(?:/li><li|br)>Velikost: <strong>(?P<S>[^<]+)</strong>'
+ OFFLINE_PATTERN = ur'<h1>Stáhnout soubor</h1><p><strong>PoşadovanÜ soubor neexistuje.</strong></p>'
+
def handleFree(self):
- 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())
+ params = {"u_ID": self.acc_info['u_ID'], "u_hash": self.acc_info['u_hash'], "link": self.pyfile.url}
- 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))
- return self.pyfile.size / 1024 <= self.acc_info["trafficleft"]
+ self.logInfo(_("User %s has %i MB left") % (self.user, self.acc_info['trafficleft'] / 1024))
+
+ return self.pyfile.size / 1024 <= self.acc_info['trafficleft']
getInfo = create_getInfo(MultishareCz)
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 6f08e6207..21d4e3e3d 100644
--- a/module/plugins/hoster/NarodRu.py
+++ b/module/plugins/hoster/NarodRu.py
@@ -1,71 +1,59 @@
# -*- 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/>.
-
- @author: zoidberg
-"""
-
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>'
- FILE_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")]
+ NAME_PATTERN = r'<dt class="name">(?:<[^<]*>)*(?P<N>[^<]+)</dt>'
+ SIZE_PATTERN = r'<dd class="size">(?P<S>\d[^<]*)</dd>'
+ OFFLINE_PATTERN = r'<title>404</title>|Ѐайл уЎалеМ с сервОса|ЗакПМчОлся срПк храМеМОя файла\.'
+
+ SIZE_REPLACEMENTS = [(u'КБ', 'KB'), (u'МБ', 'MB'), (u'ГБ', 'GB')]
+ URL_REPLACEMENTS = [("narod.yandex.ru/", "narod.ru/"),
+ (r"/start/\d+\.\w+-narod\.yandex\.ru/(\d{6,15})/\w+/(\w+)", r"/disk/\1/\2")]
CAPTCHA_PATTERN = r'<number url="(.*?)">(\w+)</number>'
- DOWNLOAD_LINK_PATTERN = r'<a class="h-link" rel="yandex_bar" href="(.+?)">'
+ 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))
- found = re.search(self.CAPTCHA_PATTERN, self.html)
- if not found:
- self.parseError('Captcha')
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
+ if m is None:
+ self.error(_("Captcha"))
post_data = {"action": "sendcapcha"}
- captcha_url, post_data['key'] = found.groups()
+ captcha_url, post_data['key'] = m.groups()
post_data['rep'] = self.decryptCaptcha(captcha_url)
self.html = self.load(self.pyfile.url, post=post_data, decode=True)
- found = re.search(self.DOWNLOAD_LINK_PATTERN, self.html)
- if found:
- url = 'http://narod.ru' + found.group(1)
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m:
+ url = 'http://narod.ru' + m.group(1)
self.correctCaptcha()
break
elif u'<b class="error-msg"><strong>ОшОблОсь?</strong>' in self.html:
self.invalidCaptcha()
else:
- self.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 4b8842d18..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,45 +45,59 @@ 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()
- if self.api_data and self.api_data["filename"]:
- self.pyfile.name = self.api_data["filename"]
+ if self.api_data and self.api_data['filename']:
+ 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,25 +125,28 @@ 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]
- self.api_data["filename"] = lines[1]
- 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()
+
+ 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]
+
+ if self.api_data['status'] == "online":
+ self.api_data['checksum'] = lines[4].strip()
else:
self.api_data = False # check manually since api data is useless sometimes
@@ -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 wait == 0:
- self.logDebug("Netload: Wait was 0 setting 30")
- wait = 30
- 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/NosuploadCom.py b/module/plugins/hoster/NosuploadCom.py
index 1de734222..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"
+
+ SIZE_PATTERN = r'<p><strong>Size:</strong> (?P<S>[\d.,]+) (?P<U>[\w^_]+)</p>'
+ LINK_PATTERN = r'<a class="select" href="(http://.+?)">Download</a>'
- FILE_SIZE_PATTERN = r'<p><strong>Size:</strong> (?P<S>[0-9\.]+) (?P<U>[kKMG]?B)</p>'
- DIRECT_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,13 +32,13 @@ 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)
# stage3: get the download link
- return re.search(self.DIRECT_LINK_PATTERN, self.html, re.S).group(1)
+ return re.search(self.LINK_PATTERN, self.html, re.S).group(1)
getInfo = create_getInfo(NosuploadCom)
diff --git a/module/plugins/hoster/NovafileCom.py b/module/plugins/hoster/NovafileCom.py
index c552c166c..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"
+ HOSTER_DOMAIN = "novafile.com"
- FILE_SIZE_PATTERN = r'<div class="size">(?P<S>.+?)</div>'
ERROR_PATTERN = r'class="alert[^"]*alert-separate"[^>]*>\s*(?:<p>)?(.*?)\s*</'
- DIRECT_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 cc1a10da0..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/>.
-
- @author: zoidberg
-"""
-
-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>'
- FILE_OFFLINE_PATTERN = r'(This file does not exist!)'
- FILE_TOKEN_PATTERN = r'"(/api/token\.php\?token=[a-z0-9]+)"'
- FILE_CONTINUE_PATTERN = r'"(/dl2/[a-z0-9]+/[a-z0-9]+)"'
- FILE_WAIT_PATTERN = r'\.countdown\(\{until: \+(\d+),'
- FILE_DOWNLOAD_LINK = 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.FILE_TOKEN_PATTERN, self.html)
- continuelink = re.search(self.FILE_CONTINUE_PATTERN, self.html)
- if not tokenlink or not continuelink:
- self.fail('Plugin out of Date')
-
- found = re.search(self.FILE_WAIT_PATTERN, self.html)
- if found:
- wait = int(found.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.FILE_DOWNLOAD_LINK, self.html)
- if not url:
- 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 1e0508d32..588d8f64a 100644
--- a/module/plugins/hoster/OboomCom.py
+++ b/module/plugins/hoster/OboomCom.py
@@ -1,52 +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 not get:
+ 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"]
+ 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,
@@ -62,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"
@@ -87,43 +117,29 @@ class OboomCom(Hoster):
result = self.loadUrl(apiUrl, params)
if result[0] == 200:
item = result[1][0]
- if item["state"] == "online":
- self.fileSize = item["size"]
- self.fileName = item["name"]
+ if item['state'] == "online":
+ self.fileSize = item['size']
+ self.fileName = item['name']
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
+ params['token'] = self.sessionToken
else:
- params["token"] = self.downloadToken
- params["auth"] = self.downloadAuth
+ params['token'] = self.downloadToken
+ params['auth'] = self.downloadAuth
result = self.loadUrl(apiUrl, params)
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 41f3e4b11..f0e16a101 100644
--- a/module/plugins/hoster/OneFichierCom.py
+++ b/module/plugins/hoster/OneFichierCom.py
@@ -1,86 +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>'
- FILE_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 = "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
- found = re.search(self.NOT_PARALLEL, self.html)
- if found:
- 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 aaa1442e4..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 b6aa77b03..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>'
- DIRECT_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 61b382c81..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,50 +25,52 @@ class PornhostCom(Hoster):
pyfile.name = self.get_file_name()
self.download(self.get_file_url())
- ### old interface
+
+ # 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
"""
- if self.html is None:
+ if not self.html:
self.download_html()
- file_url = re.search(r'download this file</label>.*?<a href="(.*?)"', self.html)
- if not file_url:
- file_url = re.search(r'"(http://dl[0-9]+\.pornhost\.com/files/.*?/.*?/.*?/.*?/.*?/.*?\..*?)"', self.html)
- if not file_url:
- file_url = re.search(r'width: 894px; height: 675px">.*?<img src="(.*?)"', self.html)
- if not file_url:
- file_url = re.search(r'"http://file[0-9]+\.pornhost\.com/[0-9]+/.*?"',
- self.html) # TODO: fix this one since it doesn't match
+ url = re.search(r'download this file</label>.*?<a href="(.*?)"', self.html)
+ if url is None:
+ 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\d+\.pornhost\.com/\d+/.*?"',
+ self.html) # TODO: fix this one since it doesn't match
- file_url = file_url.group(1).strip()
+ return url.group(1).strip()
- return file_url
def get_file_name(self):
- if self.html is None:
+ if not self.html:
self.download_html()
name = re.search(r'<title>pornhost\.com - free file hosting with a twist - gallery(.*?)</title>', self.html)
- if not name:
+ if name is None:
name = re.search(r'id="url" value="http://www\.pornhost\.com/(.*?)/"', self.html)
- if not name:
+ if name is None:
name = re.search(r'<title>pornhost\.com - free file hosting with a twist -(.*?)</title>', self.html)
- if not name:
- name = re.search(r'"http://file[0-9]+\.pornhost\.com/.*?/(.*?)"', self.html)
+ if name is None:
+ 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
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if (re.search(r'gallery not found', self.html) is not None or
diff --git a/module/plugins/hoster/PornhubCom.py b/module/plugins/hoster/PornhubCom.py
index 29205b381..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,14 +25,16 @@ 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
"""
- if self.html is None:
+ if not self.html:
self.download_html()
url = "http://www.pornhub.com//gateway.php"
@@ -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:
@@ -51,17 +57,16 @@ class PornhubCom(Hoster):
content = new_content
- file_url = re.search(r'flv_url.*(http.*?)##post_roll', content).group(1)
+ return re.search(r'flv_url.*(http.*?)##post_roll', content).group(1)
- return file_url
def get_file_name(self):
- if self.html is None:
+ if not self.html:
self.download_html()
- match = re.search(r'<title[^>]+>([^<]+) - ', self.html)
- if match:
- name = match.group(1)
+ m = re.search(r'<title[^>]+>([^<]+) - ', self.html)
+ if m:
+ name = m.group(1)
else:
matches = re.findall('<h1>(.*?)</h1>', self.html)
if len(matches) > 1:
@@ -71,10 +76,11 @@ class PornhubCom(Hoster):
return name + '.flv'
+
def file_exists(self):
""" returns True or False
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if re.search(r'This video is no longer in our database or is in conversion', self.html) is not None:
diff --git a/module/plugins/hoster/PotloadCom.py b/module/plugins/hoster/PotloadCom.py
index ffcfad1a5..d6261af3a 100644
--- a/module/plugins/hoster/PotloadCom.py
+++ b/module/plugins/hoster/PotloadCom.py
@@ -1,18 +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__ = """billionuploads.com hoster plugin"""
- __author_name__ = ("stickell")
- __author_mail__ = ("l.stickell@yahoo.it")
- FILE_INFO_PATTERN = r'<h[1-6]>(?P<N>.+) \((?P<S>\d+) (?P<U>\w+)\)</h'
- HOSTER_NAME = "potload.com"
+class PotloadCom(DeadHoster):
+ __name__ = "PotloadCom"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
+ __pattern__ = r'http://(?:www\.)?potload\.com/\w{12}'
+
+ __description__ = """Potload.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
getInfo = create_getInfo(PotloadCom)
diff --git a/module/plugins/hoster/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 3580a9509..af38c4e15 100644
--- a/module/plugins/hoster/PromptfileCom.py
+++ b/module/plugins/hoster/PromptfileCom.py
@@ -1,56 +1,45 @@
# -*- 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, create_getInfo
class PromptfileCom(SimpleHoster):
- __name__ = "PromptfileCom"
- __type__ = "hoster"
- __pattern__ = r"https?://(?:www\.)?promptfile\.com/"
- __version__ = "0.1"
- __description__ = """Promptfile.Com File Download Hoster"""
- __author_name__ = ("igel")
+ __name__ = "PromptfileCom"
+ __type__ = "hoster"
+ __version__ = "0.12"
+
+ __pattern__ = r'https?://(?:www\.)?promptfile\.com/'
+
+ __description__ = """Promptfile.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("igel", "igelkun@myopera.com")]
- FILE_INFO_PATTERN = r'<span style="[^"]*" title="[^"]*">(?P<N>.*?) \((?P<S>[\d.]+) (?P<U>\w+)\)</span>'
- FILE_OFFLINE_PATTERN = r'<span style="[^"]*" title="File Not Found">File Not Found</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="([^"]*)" />'
- DIRECT_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 not m:
- self.parseError("Unable to detect chash")
+ if m is None:
+ 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.DIRECT_LINK_PATTERN, self.html, re.MULTILINE | re.DOTALL)
- if not m:
- self.parseError("Unable to detect direct link")
- direct = m.group(1)
- self.logDebug('found direct link: ' + direct)
- self.download(direct, disposition=True)
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ 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/PutlockerCom.py b/module/plugins/hoster/PutlockerCom.py
deleted file mode 100644
index a453eaf62..000000000
--- a/module/plugins/hoster/PutlockerCom.py
+++ /dev/null
@@ -1,53 +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/>.
-#
-# @author: Walter Purcaro
-###############################################################################
-
-import re
-
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-
-
-class PutlockerCom(SimpleHoster):
- __name__ = "PutlockerCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/(mobile/)?(file|embed)/(?P<ID>\w+)'
- __version__ = "0.33"
- __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>'
- FILE_OFFLINE_PATTERN = r"<div class=\"sad_face_image\">"
-
- FILE_URL_REPLACEMENTS = [(__pattern__, r'http://www.firedrive.com/file/\g<ID>')]
-
- 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):
- self.html = self.load(self.pyfile.url, post={"confirm": re.search(r'name="confirm" value="(.*)"', self.html).group(1)})
- return re.search(r'<a href="(https?://dl\.firedrive\.com/.*?)"', self.html).group(1)
-
-
-getInfo = create_getInfo(PutlockerCom)
diff --git a/module/plugins/hoster/QuickshareCz.py b/module/plugins/hoster/QuickshareCz.py
index 46639444e..85c25f6f0 100644
--- a/module/plugins/hoster/QuickshareCz.py
+++ b/module/plugins/hoster/QuickshareCz.py
@@ -1,47 +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/>.
-
- @author: zoidberg
-"""
-
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>'
- FILE_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']
@@ -49,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:
@@ -63,12 +51,13 @@ class QuickshareCz(SimpleHoster):
check = self.checkDownload({"err": re.compile(r"\AChyba!")}, max_size=100)
if check == "err":
- self.fail("File not found or plugin defect")
+ self.fail(_("File not m or plugin defect"))
+
def handleFree(self):
# get download url
download_url = '%s/download.php' % self.jsvars['server']
- data = dict((x, self.jsvars[x]) for x in self.jsvars if x in ('ID1', 'ID2', 'ID3', 'ID4'))
+ data = dict((x, self.jsvars[x]) for x in self.jsvars if x in ("ID1", "ID2", "ID3", "ID4"))
self.logDebug("FREE URL1:" + download_url, data)
self.req.http.c.setopt(FOLLOWLOCATION, 0)
@@ -76,29 +65,29 @@ class QuickshareCz(SimpleHoster):
self.header = self.req.http.header
self.req.http.c.setopt(FOLLOWLOCATION, 1)
- found = re.search("Location\s*:\s*(.*)", self.header, re.I)
- if not found:
- self.fail('File not found')
- download_url = found.group(1)
+ 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).rstrip() #@TODO: Remove .rstrip() in 0.4.10
self.logDebug("FREE URL2:" + download_url)
# check errors
- found = re.search(r'/chyba/(\d+)', download_url)
- if found:
- if found.group(1) == '1':
+ m = re.search(r'/chyba/(\d+)', download_url)
+ if m:
+ if m.group(1) == '1':
self.retry(60, 2 * 60, "This IP is already downloading")
- elif found.group(1) == '2':
+ elif m.group(1) == '2':
self.retry(60, 60, "No free slots available")
else:
- self.fail('Error %d' % found.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)
+ data = dict((x, self.jsvars[x]) for x in self.jsvars if x in ("ID1", "ID2", "ID4", "ID5"))
self.download(download_url, get=data)
diff --git a/module/plugins/hoster/RPNetBiz.py b/module/plugins/hoster/RPNetBiz.py
index 57c22698d..bffa5ef85 100644
--- a/module/plugins/hoster/RPNetBiz.py
+++ b/module/plugins/hoster/RPNetBiz.py
@@ -2,77 +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()
+ 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("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})
+ self.logDebug("JSON data: %s" % res)
+ link_status = json_loads(res)['links'][0] # get the first link... since we only queried one
- self.logDebug("JSON data: %s" % response)
- link_status = json_loads(response)['links'][0] # get the first link... since we only queried one
+ # Check if we only have an id as a HDD link
+ if 'id' in link_status:
+ self.logDebug("Need to wait at least 30 seconds before requery")
+ self.setWait(30) # wait for 30 seconds
+ self.wait()
+ # Lets query the server again asking for the status on the link,
+ # we need to keep doing this until we reach 100
+ max_tries = 30
+ my_try = 0
+ while (my_try <= max_tries):
+ self.logDebug("Try: %d ; Max Tries: %d" % (my_try, max_tries))
+ res = self.load("https://premium.rpnet.biz/client_api.php",
+ get={"username": user,
+ "password": data['password'],
+ "action": "downloadInformation",
+ "id": link_status['id']})
+ self.logDebug("JSON data hdd query: %s" % res)
+ download_status = json_loads(res)['download']
- # 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
+ 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 b966fd1d6..ba6cfcd5c 100644
--- a/module/plugins/hoster/RapidgatorNet.py
+++ b/module/plugins/hoster/RapidgatorNet.py
@@ -1,93 +1,89 @@
# -*- 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/>.
-#
-# @author: zoidberg
-###############################################################################
import re
+
from pycurl import HTTPHEADER
from module.common.json_layer import json_loads
from module.network.HTTPRequest import BadHeader
-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.21"
+
__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>'
- FILE_OFFLINE_PATTERN = r'>(File not found|Error 404)'
+ API_URL = "http://rapidgator.net/api/file"
- JSVARS_PATTERN = r"\s+var\s*(startTimerUrl|getDownloadUrl|captchaUrl|fid|secs)\s*=\s*'?(.*?)'?;"
+ COOKIES = [("rapidgator.net", "lang", "en")]
+
+ NAME_PATTERN = r'<title>Download file (?P<N>.*)</title>'
+ SIZE_PATTERN = r'File size:\s*<strong>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong>'
+ OFFLINE_PATTERN = r'>(File not found|Error 404)'
+
+ JSVARS_PATTERN = r'\s+var\s*(startTimerUrl|getDownloadUrl|captchaUrl|fid|secs)\s*=\s*\'?(.*?)\'?;'
PREMIUM_ONLY_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)'
- DOWNLOAD_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')
@@ -97,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))
@@ -109,13 +104,13 @@ class RapidgatorNet(SimpleHoster):
self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"])
url = "http://rapidgator.net%s?fid=%s" % (
- jsvars.get('startTimerUrl', '/download/AjaxStartTimer'), jsvars["fid"])
+ jsvars.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"])
+ jsvars.get('getDownloadUrl', '/download/AjaxGetDownload'), jsvars['sid'])
jsvars.update(self.getJsonResponse(url))
self.req.http.lastURL = self.pyfile.url
@@ -124,78 +119,80 @@ class RapidgatorNet(SimpleHoster):
url = "http://rapidgator.net%s" % jsvars.get('captchaUrl', '/download/captcha')
self.html = self.load(url)
- for _ in xrange(5):
- found = re.search(self.DOWNLOAD_LINK_PATTERN, self.html)
- if found:
- link = found.group(1)
+ for _i in xrange(5):
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m:
+ link = m.group(1)
self.logDebug(link)
self.download(link, disposition=True)
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):
- found = re.search(self.ADSCAPTCHA_SRC_PATTERN, self.html)
- if found:
- captcha_key = found.group(1)
+ m = re.search(self.ADSCAPTCHA_PATTERN, self.html)
+ if m:
+ captcha_key = m.group(1)
captcha = AdsCaptcha(self)
else:
- found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html)
- if found:
- captcha_key = found.group(1)
+ m = re.search(self.RECAPTCHA_PATTERN, self.html)
+ if m:
+ captcha_key = m.group(1)
captcha = ReCaptcha(self)
else:
- found = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if found:
- captcha_key = found.group(1)
+ m = re.search(self.SOLVEMEDIA_PATTERN, self.html)
+ if m:
+ captcha_key = m.group(1)
captcha = SolveMedia(self)
else:
- self.parseError("Captcha")
+ self.error(_("Captcha"))
return captcha, captcha_key
+
def checkFree(self):
- found = re.search(self.PREMIUM_ONLY_ERROR_PATTERN, self.html)
- if found:
- self.fail("Premium account needed for download")
+ m = re.search(self.PREMIUM_ONLY_ERROR_PATTERN, self.html)
+ if m:
+ self.fail(_("Premium account needed for download"))
else:
- found = re.search(self.WAIT_PATTERN, self.html)
+ m = re.search(self.WAIT_PATTERN, self.html)
- if found:
- wait_time = int(found.group(1)) * {"hour": 60, "min": 1}[found.group(2)]
+ if m:
+ wait_time = int(m.group(1)) * {"hour": 60, "min": 1}[m.group(2)]
else:
- found = re.search(self.DOWNLOAD_LIMIT_ERROR_PATTERN, self.html)
- if not found:
+ m = re.search(self.DOWNLOAD_LIMIT_ERROR_PATTERN, self.html)
+ if m is None:
return
- elif found.group(1) == "daily":
- wait_time = 60
+ elif m.group(1) == "daily":
+ self.logWarning(_("You have reached your daily downloads limit for today"))
+ wait_time = secondsToMidnight(gmt=2)
else:
- wait_time = 24 * 60
+ wait_time = 1 * 60 * 60
- self.logDebug("Waiting %d minutes" % wait_time)
- self.wait(wait_time * 60, True)
+ self.logDebug("Waiting %d minutes" % wait_time / 60)
+ 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 e5ab6b445..000000000
--- a/module/plugins/hoster/RapidshareCom.py
+++ /dev/null
@@ -1,228 +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 8f2aacbcf..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;'
- DIRECT_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 36fcd194c..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 a2bbf3883..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,31 +26,34 @@ 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
"""
- if self.html is None:
+ if not self.html:
self.download_html()
file_url = unescape(re.search(r'hashlink=(http.*?)"', self.html).group(1))
return file_url
+
def get_file_name(self):
- if self.html is None:
+ if not self.html:
self.download_html()
- name = re.search('<title>(.*?)- RedTube - Free Porn Videos</title>', self.html).group(1).strip() + ".flv"
- return name
+ return re.search('<title>(.*?)- RedTube - Free Porn Videos</title>', self.html).group(1).strip() + ".flv"
+
def file_exists(self):
""" returns True or False
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if re.search(r'This video has been removed.', self.html) is not None:
diff --git a/module/plugins/hoster/RehostTo.py b/module/plugins/hoster/RehostTo.py
index 94e53520a..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, ""))
+ long_ses = data['long_ses']
#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/ReloadCc.py b/module/plugins/hoster/ReloadCc.py
deleted file mode 100644
index ed1b21aa3..000000000
--- a/module/plugins/hoster/ReloadCc.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from module.plugins.Hoster import Hoster
-
-from module.common.json_layer import json_loads
-
-from module.network.HTTPRequest import BadHeader
-
-
-class ReloadCc(Hoster):
- __name__ = "ReloadCc"
- __version__ = "0.5"
- __type__ = "hoster"
- __description__ = """Reload.cc hoster plugin"""
-
- # 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 ReloadCc hook.
- __pattern__ = None
-
- __author_name__ = "Reload Team"
- __author_mail__ = "hello@reload.cc"
-
- 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") % "reload.cc")
- self.fail("No valid reload.cc account provided")
-
- # In some cases hostsers do not supply us with a filename at download, so we
- # are going to set a fall back filename (e.g. for freakshare or xfileshare)
- pyfile.name = pyfile.name.split('/').pop() # Remove everthing before last slash
-
- # Correction for automatic assigned filename: Removing html at end if needed
- suffix_to_remove = ["html", "htm", "php", "php3", "asp", "shtm", "shtml", "cfml", "cfm"]
- temp = pyfile.name.split('.')
- if temp.pop() in suffix_to_remove:
- pyfile.name = ".".join(temp)
-
- # Get account data
- (user, data) = self.account.selectAccount()
-
- query_params = dict(
- via='pyload',
- v=1,
- user=user,
- uri=pyfile.url
- )
-
- try:
- query_params.update(dict(hash=self.account.infos[user]['pwdhash']))
- except Exception:
- query_params.update(dict(pwd=data['password']))
-
- try:
- answer = self.load("http://api.reload.cc/dl", get=query_params)
- except BadHeader, e:
- if e.code == 400:
- self.fail("The URI is not supported by Reload.cc.")
- elif e.code == 401:
- self.fail("Wrong username or password")
- elif e.code == 402:
- self.fail("Your account is inactive. A payment is required for downloading!")
- elif e.code == 403:
- self.fail("Your account is disabled. Please contact the Reload.cc support!")
- elif e.code == 409:
- self.logWarning("The hoster seems to be a limited hoster and you've used your daily traffic for this hoster: %s" % pyfile.url)
- # Wait for 6 hours and retry up to 4 times => one day
- self.retry(4, 6 * 60 * 60, "Limited hoster traffic limit exceeded")
- elif e.code == 429:
- # Too many connections, wait 2 minutes and try again
- self.retry(5, 2 * 60, "Too many concurrent connections")
- elif e.code == 503:
- # Retry in 10 minutes
- self.retry(wait_time=10 * 60,
- reason="Reload.cc is currently in maintenance mode! Please check again later.")
- else:
- self.fail(
- "Internal error within Reload.cc. Please contact the Reload.cc support for further information.")
- return
-
- data = json_loads(answer)
-
- # Check status and decide what to do
- status = data.get('status', None)
- if status == "ok":
- conn_limit = data.get('msg', 0)
- # API says these connections are limited
- # Make sure this limit is used - the download will fail if not
- if conn_limit > 0:
- try:
- self.limitDL = int(conn_limit)
- except ValueError:
- self.limitDL = 1
- else:
- self.limitDL = 0
-
- try:
- self.download(data['link'], disposition=True)
- except BadHeader, e:
- if e.code == 404:
- self.fail("File Not Found")
- elif e.code == 412:
- self.fail("File access password is wrong")
- elif e.code == 417:
- self.fail("Password required for file access")
- elif e.code == 429:
- # Too many connections, wait 2 minutes and try again
- self.retry(5, 2 * 60, "Too many concurrent connections")
- else:
- self.fail(
- "Internal error within Reload.cc. Please contact the Reload.cc support for further information."
- )
- return
- else:
- self.fail("Internal error within Reload.cc. Please contact the Reload.cc support for further information.")
diff --git a/module/plugins/hoster/RemixshareCom.py b/module/plugins/hoster/RemixshareCom.py
new file mode 100644
index 000000000..ed171895e
--- /dev/null
+++ b/module/plugins/hoster/RemixshareCom.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+#
+# Test links:
+# http://remixshare.com/download/p946u
+#
+# Note:
+# The remixshare.com website is very very slow, so
+# if your download not starts because of pycurl timeouts:
+# Adjust timeouts in /usr/share/pyload/module/network/HTTPRequest.py
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class RemixshareCom(SimpleHoster):
+ __name__ = "RemixshareCom"
+ __type__ = "hoster"
+ __version__ = "0.02"
+
+ __pattern__ = r'https?://remixshare\.com/(download|dl)/\w+'
+
+ __description__ = """Remixshare.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ INFO_PATTERN = r'title=\'.+?\'>(?P<N>.+?)</span><span class=\'light2\'>&nbsp;\((?P<S>\d+)&nbsp;(?P<U>[\w^_]+)\)<'
+ OFFLINE_PATTERN = r'<h1>Ooops!<'
+
+ LINK_PATTERN = r'(http://remixshare\.com/downloadfinal/.+?)"'
+ TOKEN_PATTERN = r'var acc = (\d+)'
+ WAIT_PATTERN = r'var XYZ = r"(\d+)"'
+
+
+ def setup(self):
+ self.multiDL = True
+ self.chunkLimit = 1
+
+
+ def handleFree(self):
+ b = re.search(self.LINK_PATTERN, self.html)
+ if not b:
+ self.error(_("Cannot parse download url"))
+ c = re.search(self.TOKEN_PATTERN, self.html)
+ if not c:
+ self.error(_("Cannot parse file token"))
+ 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(int(seconds.group(1)))
+
+ # Finally start downloading...
+ self.download(dl_url, disposition=True)
+
+
+getInfo = create_getInfo(RemixshareCom)
diff --git a/module/plugins/hoster/RgHostNet.py b/module/plugins/hoster/RgHostNet.py
index 9e37ed87b..aa4830563 100644
--- a/module/plugins/hoster/RgHostNet.py
+++ b/module/plugins/hoster/RgHostNet.py
@@ -1,27 +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"
-
- FILE_INFO_PATTERN = r'<h1>\s+(<a[^>]+>)?(?P<N>[^<]+)(</a>)?\s+<small[^>]+>\s+\((?P<S>[^)]+)\)\s+</small>\s+</h1>'
- FILE_OFFLINE_PATTERN = r'File is deleted|this page is not found'
- DOWNLOAD_LINK_PATTERN = '''<a\s+href="([^"]+)"\s+class="btn\s+large\s+download"[^>]+>Download</a>'''
-
- def handleFree(self):
- found = re.search(self.DOWNLOAD_LINK_PATTERN, self.html)
- if not found:
- self.parseError("Unable to detect the direct link")
- download_link = found.group(1)
- self.download(download_link, disposition=True)
+ __license__ = "GPLv3"
+ __authors__ = [("z00nx", "z00nx0@gmail.com")]
+
+
+ INFO_PATTERN = r'<h1>\s+(<a[^>]+>)?(?P<N>[^<]+)(</a>)?\s+<small[^>]+>\s+\((?P<S>[^)]+)\)\s+</small>\s+</h1>'
+ OFFLINE_PATTERN = r'File is deleted|this page is not found'
+
+ LINK_FREE_PATTERN = r'<a\s+href="([^"]+)"\s+class="btn\s+large\s+download"[^>]+>Download</a>'
+
getInfo = create_getInfo(RgHostNet)
diff --git a/module/plugins/hoster/RyushareCom.py b/module/plugins/hoster/RyushareCom.py
index 4d3e9b7f3..0964c51fc 100644
--- a/module/plugins/hoster/RyushareCom.py
+++ b/module/plugins/hoster/RyushareCom.py
@@ -1,37 +1,41 @@
# -*- 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]'
- DIRECT_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
self.html = self.load(self.pyfile.url)
action, inputs = self.parseHtmlForm(input_names={"op": re.compile("^download")})
if "method_premium" in inputs:
- del inputs["method_premium"]
+ del inputs['method_premium']
self.html = self.load(self.pyfile.url, post=inputs)
action, inputs = self.parseHtmlForm('F1')
@@ -42,10 +46,10 @@ class RyushareCom(XFileSharingPro):
self.setWait(1 * 60 * 60, True)
retry = True
- match = re.search(self.WAIT_PATTERN, self.html)
- if match:
- m = match.groupdict(0)
- waittime = int(m["hour"]) * 60 * 60 + int(m["min"]) * 60 + int(m["sec"])
+ m = re.search(self.WAIT_PATTERN, self.html)
+ if m:
+ wait = m.groupdict(0)
+ waittime = int(wait['H']) * 60 * 60 + int(wait['M']) * 60 + int(wait['S'])
self.setWait(waittime, True)
retry = True
@@ -53,31 +57,24 @@ class RyushareCom(XFileSharingPro):
if retry:
self.retry()
- for _ in xrange(5):
- m = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if not m:
- 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
+ inputs['adcopy_challenge'] = challenge
+ inputs['adcopy_response'] = response
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:
- m = re.search(r'<a href="([^"]+)">Click here to download</a>', self.html)
- return m.group(1)
+ return re.search(r'<a href="([^"]+)">Click here to download</a>', self.html).group(1)
getInfo = create_getInfo(RyushareCom)
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 1b11d691d..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 = '<h3>Downloading (?P<N>[^<]+) \((?P<S>[^<]+)\)</h3>'
- FILE_OFFLINE_PATTERN = '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 d6eafac0c..12f966e31 100644
--- a/module/plugins/hoster/SendspaceCom.py
+++ b/module/plugins/hoster/SendspaceCom.py
@@ -1,60 +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/>.
-
- @author: zoidberg
-"""
-
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")]
+
+
+ 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>'
- DOWNLOAD_URL_PATTERN = r'<a id="download_button" href="([^"]+)"'
- 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>'
- FILE_OFFLINE_PATTERN = r'<div class="msg error" style="cursor: default">Sorry, the file you requested is not available.</div>'
- 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):
- found = re.search(self.DOWNLOAD_URL_PATTERN, self.html)
- if found:
+ for _i in xrange(3):
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m:
if 'captcha_hash' in params:
self.correctCaptcha()
- download_url = found.group(1)
+ download_url = m.group(1)
break
- found = re.search(self.CAPTCHA_PATTERN, self.html)
- if found:
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
+ if m:
if 'captcha_hash' in params:
self.invalidCaptcha()
- captcha_url1 = "http://www.sendspace.com/" + found.group(1)
- found = re.search(self.USER_CAPTCHA_PATTERN, self.html)
- captcha_url2 = "http://www.sendspace.com/" + found.group(1)
- params = {'captcha_hash': found.group(2),
+ captcha_url1 = "http://www.sendspace.com/" + m.group(1)
+ m = re.search(self.USER_CAPTCHA_PATTERN, self.html)
+ captcha_url2 = "http://www.sendspace.com/" + m.group(1)
+ params = {'captcha_hash': m.group(2),
'captcha_submit': 'Verify',
'captcha_answer': self.decryptCaptcha(captcha_url1) + " " + self.decryptCaptcha(captcha_url2)}
else:
@@ -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 e25216cb8..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")]
+
- DOMAIN = 'http://www.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 558ec2451..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__ = ""
+ __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/ShareRapidCom.py b/module/plugins/hoster/ShareRapidCom.py
deleted file mode 100644
index b82a142ea..000000000
--- a/module/plugins/hoster/ShareRapidCom.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-
-from pycurl import HTTPHEADER
-from module.network.HTTPRequest import BadHeader
-from module.network.RequestFactory import getRequest
-from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo, replace_patterns
-
-
-def getInfo(urls):
- h = getRequest()
- h.c.setopt(HTTPHEADER,
- ["Accept: text/html",
- "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0"])
- for url in urls:
- html = h.load(url, decode=True)
- file_info = parseFileInfo(ShareRapidCom, replace_patterns(url, ShareRapidCom.FILE_URL_REPLACEMENTS), html)
- yield file_info
-
-
-class ShareRapidCom(SimpleHoster):
- __name__ = "ShareRapidCom"
- __type__ = "hoster"
- __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)/stahuj/(?P<id>\w+)'
- __version__ = "0.53"
- __description__ = """Share-rapid.com hoster plugin"""
- __author_name__ = ("MikyWoW", "zoidberg", "stickell")
- __author_mail__ = ("mikywow@seznam.cz", "zoidberg@mujmail.cz", "l.stickell@yahoo.it")
-
- 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>'
- FILE_OFFLINE_PATTERN = ur'Nastala chyba 404|Soubor byl smazán'
-
- DOWNLOAD_URL_PATTERN = r'<a href="([^"]+)" title="Stahnout">([^<]+)</a>'
- ERR_LOGIN_PATTERN = ur'<div class="error_div"><strong>Stahování je přístupné pouze přihlášenÃœm uÅŸivatelům'
- ERR_CREDIT_PATTERN = ur'<div class="error_div"><strong>Stahování zdarma je moÅŸné jen přes náš'
-
- FILE_URL_REPLACEMENTS = [(__pattern__, r'http://share-rapid.com/stahuj/\g<id>')]
-
- def setup(self):
- self.chunkLimit = 1
- self.resumeDownload = True
-
- def process(self, pyfile):
- if not self.account:
- self.fail("User not logged in")
-
- try:
- self.html = self.load(pyfile.url, decode=True)
- except BadHeader, e:
- self.account.relogin(self.user)
- self.retry(max_tries=3, reason=str(e))
-
- self.getFileInfo()
-
- found = re.search(self.DOWNLOAD_URL_PATTERN, self.html)
- if found:
- link = found.group(1)
- self.logDebug("Premium link: %s" % link)
-
- self.download(link, disposition=True)
- else:
- if re.search(self.ERR_LOGIN_PATTERN, self.html):
- self.relogin(self.user)
- self.retry(max_tries=3, reason="User login failed")
- elif re.search(self.ERR_CREDIT_PATTERN, self.html):
- self.fail("Not enough credit left")
- else:
- self.fail("Download link not found")
diff --git a/module/plugins/hoster/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 a5bd9c250..dc3d5093c 100644
--- a/module/plugins/hoster/ShareonlineBiz.py
+++ b/module/plugins/hoster/ShareonlineBiz.py
@@ -1,195 +1,188 @@
# -*- 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
+
+ return info
- self.html = self.load("%s/free/" % self.pyfile.url, post={"dl_free": "1", "choice": "free"}, decode=True)
- self.checkErrors()
- found = re.search(r'var wait=(\d+);', self.html)
+ def setup(self):
+ self.resumeDownload = self.premium
+ self.multiDL = False
+
+ def handleCaptcha(self):
recaptcha = ReCaptcha(self)
- for _ in xrange(5):
- challenge, response = recaptcha.challenge("6LdatrsSAAAAAHZrB70txiV5p-8Iv8BtVxlTtjKX")
- self.setWait(int(found.group(1)) if found 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':
+
+ 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)
+
+ 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
+ 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",
- {"username": self.user, "password": self.account.accounts[self.user]["password"],
- "act": "download", "lid": self.file_id})
+
+ html = self.load("http://api.share-online.biz/account.php",
+ {"username": self.user, "password": self.account.accounts[self.user]['password'],
+ "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":
+
+ if not dlinfo['status'] == "online":
self.offline()
else:
- self.pyfile.name = dlinfo["name"]
- self.pyfile.size = int(dlinfo["size"])
+ self.pyfile.name = dlinfo['name']
+ self.pyfile.size = int(dlinfo['size'])
+
+ dlLink = dlinfo['url']
- dlLink = dlinfo["url"]
if dlLink == "server_under_maintenance":
self.tempOffline()
else:
self.multiDL = True
self.download(dlLink)
+
def checkErrors(self):
- found = re.search(r"/failure/(.*?)/1", self.req.lastEffectiveURL)
- if not found:
+ m = re.search(r"/failure/(.*?)/1", self.req.lastEffectiveURL)
+ if m is None:
+ self.info.pop('error', None)
return
- err = found.group(1)
- found = re.search(self.ERROR_INFO_PATTERN, self.html)
- msg = found.group(1) if found 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 in ('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 ba1b40fb7..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__ = ""
+ __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,11 +33,11 @@ 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 self.html is None:
+ if not self.html:
self.download_html()
#var zzipitime = 15;
@@ -43,34 +49,38 @@ 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 self.html is None:
+ if not self.html:
self.download_html()
return re.search("<title>\s*(.*?)\s*</title>", self.html).group(1)
+
def file_exists(self):
""" returns True or False
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if re.search(r"HTTP Status 404", self.html) is not None:
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 c9fbf2ff1..bf7c43af6 100644
--- a/module/plugins/hoster/SimplyPremiumCom.py
+++ b/module/plugins/hoster/SimplyPremiumCom.py
@@ -1,103 +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.internal.MultiHoster import MultiHoster, create_getInfo
+from module.plugins.internal.SimpleHoster import secondsToMidnight
-def secondsToMidnight():
- # Seconds until 00:10 GMT+2
- now = datetime.utcnow() + timedelta(hours=2)
- 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 SimplyPremiumCom(MultiHoster):
+ __name__ = "SimplyPremiumCom"
+ __type__ = "hoster"
+ __version__ = "0.07"
+ __pattern__ = r'https?://.+simply-premium\.com'
+
+ __description__ = """Simply-Premium.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("EvolutionClip", "evolutionclip@live.de")]
-class SimplyPremiumCom(Hoster):
- __name__ = "SimplyPremiumCom"
- __version__ = "0.01"
- __type__ = "hoster"
- __pattern__ = r"https?://.*(simply-premium)\.com"
- __description__ = """Simply-Premium.Com hoster plugin"""
- __author_name__ = ("EvolutionClip")
- __author_mail__ = ("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.logInfo("Reached maximum connctions")
- self.retry(5, 60, "Reached maximum connctions")
- elif "trafficlimit" in page:
- self.logInfo("Reached daily limit for this host. Waiting until 00:10 GMT+2")
- self.retry(5, secondsToMidnight(), "Daily limit for this host reached")
- elif "hostererror" 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]
-
- try:
- start = page.index('<name>') + len('<name>')
- end = page.index('</name>', start)
- self.pyfile.name = page[start:end]
- except ValueError:
- self.pyfile.name = ""
-
- try:
- start = page.index('<size>') + len('<size>')
- end = page.index('</size>', start)
- self.pyfile.size = int(float(page[start:end]))
- except ValueError:
- self.pyfile.size = 0
-
- 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 017c8a839..aabb8dcd1 100644
--- a/module/plugins/hoster/SockshareCom.py
+++ b/module/plugins/hoster/SockshareCom.py
@@ -1,96 +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/>.
-#
-# @author: Walter Purcaro
-###############################################################################
-import re
-from os import rename
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+class SockshareCom(DeadHoster):
+ __name__ = "SockshareCom"
+ __type__ = "hoster"
+ __version__ = "0.05"
-class SockshareCom(SimpleHoster):
- __name__ = "SockshareCom"
- __type__ = "hoster"
__pattern__ = r'http://(?:www\.)?sockshare\.com/(mobile/)?(file|embed)/(?P<ID>\w+)'
- __version__ = "0.02"
- __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>'
- FILE_OFFLINE_PATTERN = r'>This file doesn\'t exist, or has been removed.<'
-
- 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 or
- "(>This content server has been temporarily disabled for upgrades|Try again soon\\. You can still download it below\\.<)" in self.html):
- self.retry(wait_time=60 * 60 * 2, reason="Download limit exceeded or server disabled") # 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 not link:
- 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})
+ __description__ = """Sockshare.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("jeix", "jeix@hasnomail.de"),
+ ("stickell", "l.stickell@yahoo.it"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
getInfo = create_getInfo(SockshareCom)
diff --git a/module/plugins/hoster/SoundcloudCom.py b/module/plugins/hoster/SoundcloudCom.py
index a1ec1378a..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)
- match = 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 match:
- songId = match.group("ID")
+ if m:
+ 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:
- match = re.search(r'"clientID":"(?P<CID>.*?)"', page)
- if match:
- clientId = match.group("CID")
+ m = re.search(r'"clientID":"(?P<CID>.*?)"', page)
+ if m:
+ clientId = m.group('CID')
if len(clientId) <= 0:
clientId = "b45b1aa10f1ac2941910a7f0d10f8e28"
- match = re.search(r'<em itemprop="name">\s(?P<TITLE>.*?)\s</em>', page)
- if match:
- pyfile.name = match.group("TITLE") + ".mp3"
+ m = re.search(r'<em itemprop="name">\s(?P<TITLE>.*?)\s</em>', page)
+ if m:
+ 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 63e126f0a..f23c8d4c7 100644
--- a/module/plugins/hoster/SpeedfileCz.py
+++ b/module/plugins/hoster/SpeedfileCz.py
@@ -1,33 +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/>.
-
- @author: zoidberg
-"""
-
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 bbef31a67..11d4efcdb 100644
--- a/module/plugins/hoster/StreamCz.py
+++ b/module/plugins/hoster/StreamCz.py
@@ -1,25 +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/>.
-
- @author: zoidberg
-"""
-
import re
-from module.plugins.Hoster import Hoster
+
from module.network.RequestFactory import getURL
+from module.plugins.Hoster import Hoster
def getInfo(urls):
@@ -28,7 +12,7 @@ def getInfo(urls):
for url in urls:
html = getURL(url)
- if re.search(StreamCz.FILE_OFFLINE_PATTERN, html):
+ if re.search(StreamCz.OFFLINE_PATTERN, html):
# File offline
result.append((url, 0, 1, url))
else:
@@ -37,46 +21,51 @@ def getInfo(urls):
class StreamCz(Hoster):
- __name__ = "StreamCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?stream.cz/[^/]+/\d+.*'
- __version__ = "0.1"
+ __name__ = "StreamCz"
+ __type__ = "hoster"
+ __version__ = "0.20"
+
+ __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")]
+
+
+ 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>'
- FILE_OFFLINE_PATTERN = r'<h1 class="commonTitle">Str.nku nebylo mo.n. nal.zt \(404\)</h1>'
- FILE_NAME_PATTERN = r'<link rel="video_src" href="http://www.stream.cz/\w+/(\d+)-([^"]+)" />'
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.FILE_OFFLINE_PATTERN, self.html):
+ if re.search(self.OFFLINE_PATTERN, self.html):
self.offline()
- found = re.search(self.CDN_PATTERN, self.html)
- if found is None:
- self.fail("Parse error (CDN)")
- cdn = found.groupdict()
+ m = re.search(self.CDN_PATTERN, self.html)
+ if m is None:
+ self.error(_("CDN_PATTERN not found"))
+ cdn = m.groupdict()
self.logDebug(cdn)
for cdnkey in ("cdnHD", "cdnHQ", "cdnLQ"):
if cdnkey in cdn and cdn[cdnkey] > '':
cdnid = cdn[cdnkey]
break
else:
- self.fail("Stream URL not found")
+ self.fail(_("Stream URL not found"))
- found = re.search(self.FILE_NAME_PATTERN, self.html)
- if found is None:
- self.fail("Parse error (NAME)")
- pyfile.name = "%s-%s.%s.mp4" % (found.group(2), found.group(1), cdnkey[-2:])
+ m = re.search(self.NAME_PATTERN, self.html)
+ if m is None:
+ 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 388eb7876..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"
-
- DIRECT_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):
- found = re.search(self.DIRECT_LINK_PATTERN, self.html, re.S)
- if found:
- return found.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
-
- found = re.search("Location\s*:\s*(.*)", self.header, re.I)
- if found:
- break
-
- found = re.search(self.DIRECT_LINK_PATTERN, self.html, re.S)
- if found:
- 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 found.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:
- found = re.search(self.WAIT_PATTERN, self.html)
- if found:
- wait_time = int(found.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 f15b8b0c4..258ec7d3e 100644
--- a/module/plugins/hoster/TurbobitNet.py
+++ b/module/plugins/hoster/TurbobitNet.py
@@ -1,63 +1,49 @@
# -*- coding: utf-8 -*-
-"""
- Copyright (C) 2012 pyLoad team
- Copyright (C) 2012 JD-Team support@jdownloader.org
-
- 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/>.
-
- @author: zoidberg
-"""
-
-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"
-
- # long filenames are shortened
- FILE_INFO_PATTERN = r"<span class='file-icon1[^>]*>(?P<N>[^<]+)</span>\s*\((?P<S>[^\)]+)\)\s*</h1>"
- FILE_NAME_PATTERN = r'<meta name="keywords" content="\s+(?P<N>[^,]+)' # full name but missing on page2
- FILE_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")]
-
- CAPTCHA_KEY_PATTERN = r'src="http://api\.recaptcha\.net/challenge\?k=([^"]+)"'
- DOWNLOAD_URL_PATTERN = r'(?P<url>/download/redirect/[^"\']+)'
- LIMIT_WAIT_PATTERN = r'<div id="time-limit-text">\s*.*?<span id=\'timeout\'>(\d+)</span>'
- CAPTCHA_SRC_PATTERN = r'<img alt="Captcha" src="(.*?)"'
+ __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'
+
+ LINK_PATTERN = r'(/download/redirect/[^"\']+)'
+ LIMIT_WAIT_PATTERN = r'<div id=\'timeout\'>(\d+)<'
+
+ 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()
@@ -70,79 +56,81 @@ class TurbobitNet(SimpleHoster):
self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"])
self.downloadFile()
+
def solveCaptcha(self):
- for _ in xrange(5):
- found = re.search(self.LIMIT_WAIT_PATTERN, self.html)
- if found:
- wait_time = int(found.group(1))
+ for _i in xrange(5):
+ m = re.search(self.LIMIT_WAIT_PATTERN, self.html)
+ if m:
+ wait_time = int(m.group(1))
self.wait(wait_time, wait_time > 60)
self.retry()
action, inputs = self.parseHtmlForm("action='#'")
if not inputs:
- self.parseError("captcha form")
+ self.error(_("Captcha form not found"))
self.logDebug(inputs)
if inputs['captcha_type'] == 'recaptcha':
recaptcha = ReCaptcha(self)
- found = re.search(self.CAPTCHA_KEY_PATTERN, self.html)
- captcha_key = found.group(1) if found 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:
- found = re.search(self.CAPTCHA_SRC_PATTERN, self.html)
- if not found:
- self.parseError('captcha')
- captcha_url = found.group(1)
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
+ if m is None:
+ self.error(_("captcha"))
+ captcha_url = m.group(1)
inputs['captcha_response'] = self.decryptCaptcha(captcha_url)
self.logDebug(inputs)
self.html = self.load(self.url, post=inputs)
- if 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
- found = re.search("(/\w+/timeout\.js\?\w+=)([^\"\'<>]+)", self.html)
- url = "http://turbobit.net%s%s" % (found.groups() if found else (
- '/files/timeout.js?ver=', ''.join(random.choice('0123456789ABCDEF') for _ in xrange(32))))
+ m = re.search("(/\w+/timeout\.js\?\w+=)([^\"\'<>]+)", self.html)
+ if m:
+ url = "http://turbobit.net%s%s" % m.groups()
+ else:
+ url = "http://turbobit.net/files/timeout.js?ver=%s" % "".join(random.choice('0123456789ABCDEF') for _i in xrange(32))
+
fun = self.load(url)
self.setWait(65, False)
for b in [1, 3]:
self.jscode = "var id = \'%s\';var b = %d;var inn = \'%s\';%sout" % (
- self.file_info['ID'], b, quote(fun), rtUpdate)
+ self.info['pattern']['ID'], b, quote(fun), rtUpdate)
try:
out = self.js.eval(self.jscode)
@@ -157,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):
- found = re.search(self.DOWNLOAD_URL_PATTERN, self.html)
- if not found:
- self.parseError("download link")
- self.url = "http://turbobit.net" + found.group('url')
- self.logDebug(self.url)
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ 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 3f3deca15..f0893cef6 100644
--- a/module/plugins/hoster/TurbouploadCom.py
+++ b/module/plugins/hoster/TurbouploadCom.py
@@ -1,33 +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/>.
-
- @author: zoidberg
-"""
-
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 c31b88f20..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+)\['
- FILE_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 7881ca098..1dd67f974 100644
--- a/module/plugins/hoster/TwoSharedCom.py
+++ b/module/plugins/hoster/TwoSharedCom.py
@@ -6,29 +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")]
+
+
+ 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 =\'(.+?)\';'
- 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'
- FILE_OFFLINE_PATTERN = r'The file link that you requested is not valid\.|This file was deleted\.'
- DOWNLOAD_URL_PATTERN = r"window.location ='([^']+)';"
def setup(self):
- self.resumeDownload = self.multiDL = True
+ self.resumeDownload = True
+ self.multiDL = True
+
def handleFree(self):
- found = re.search(self.DOWNLOAD_URL_PATTERN, self.html)
- if not found:
- self.parseError('Download link')
- link = found.group(1)
- self.logDebug("Download URL %s" % link)
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ 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 282d4605b..6b84a5e1b 100644
--- a/module/plugins/hoster/UlozTo.py
+++ b/module/plugins/hoster/UlozTo.py
@@ -1,26 +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/>.
-
- @author: zoidberg
-"""
-
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
@@ -28,61 +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"
-
- 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>'
- FILE_INFO_PATTERN = r'<p>File <strong>(?P<N>[^<]+)</strong> is password protected</p>'
- FILE_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")]
-
- ADULT_PATTERN = r'<form action="(?P<link>[^\"]*)" method="post" id="frm-askAgeForm">'
- PASSWD_PATTERN = r'<div class="passwordProtectedFile">'
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ INFO_PATTERN = r'<p>File <strong>(?P<N>[^<]+)</strong> is password protected</p>'
+ NAME_PATTERN = r'<title>(?P<N>[^<]+) \| Uloz\.to</title>'
+ SIZE_PATTERN = r'<span id="fileSize">.*?(?P<S>[\d.,]+\s[kMG]?B)</span>'
+ OFFLINE_PATTERN = r'<title>404 - Page not found</title>|<h1 class="h1">File (has been deleted|was banned)</h1>'
+
+ URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "www.ulozto.net")]
+ SIZE_REPLACEMENTS = [('([\d.]+)\s([kMG])B', convertDecimalPrefix)]
+
+ ADULT_PATTERN = r'<form action="([^\"]*)" method="post" id="frm-askAgeForm">'
+ PASSWD_PATTERN = r'<div class="passwordProtectedFile">'
VIPLINK_PATTERN = r'<a href="[^"]*\?disclaimer=1" class="linkVip">'
- 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"))
- found = re.search(self.TOKEN_PATTERN, self.html)
- if not found:
- self.parseError('TOKEN')
- token = found.group(1)
+ m = re.search(self.TOKEN_PATTERN, self.html)
+ if m is None:
+ self.error(_("TOKEN_PATTERN not found"))
+ token = m.group(1)
self.html = self.load(pyfile.url, get={"do": "askAgeForm-submit"},
post={"agree": "Confirm", "_token_": token}, cookies=True)
- 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,58 +86,62 @@ 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')):
+ 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})
- elif all(key in inputs for key in ('captcha_value', 'timestamp', 'salt', 'hash')):
+ elif all(key in inputs for key in ("captcha_value", "timestamp", "salt", "hash")):
# New version - better to get new parameters (like captcha reload) because of image url - since 6.12.2013
self.logDebug('Using "new" version')
xapca = self.load("http://www.ulozto.net/reloadXapca.php", get={"rnd": str(int(time.time()))})
- self.logDebug('xapca = ' + str(xapca))
+ 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")
- found = re.search(self.PREMIUM_URL_PATTERN if premium else self.FREE_URL_PATTERN, self.html)
- if not found:
- self.parseError(msg)
- parsed_url = "http://www.ulozto.net" + found.group(1)
+ 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.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>'),
- "offline": re.compile(self.FILE_OFFLINE_PATTERN),
+ "offline": re.compile(self.OFFLINE_PATTERN),
"passwd": self.PASSWD_PATTERN,
"server_error": 'src="http://img.ulozto.cz/error403/vykricnik.jpg"', # paralell dl, server overload etc.
"not_found": "<title>UloÅŸ.to</title>"
@@ -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 d24e21779..0afa4e5a5 100644
--- a/module/plugins/hoster/UloziskoSk.py
+++ b/module/plugins/hoster/UloziskoSk.py
@@ -1,75 +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.
+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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
- @author: zoidberg
-"""
-import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError
+class UloziskoSk(SimpleHoster):
+ __name__ = "UloziskoSk"
+ __type__ = "hoster"
+ __version__ = "0.24"
+ __pattern__ = r'http://(?:www\.)?ulozisko\.sk/.+'
-class UloziskoSk(SimpleHoster):
- __name__ = "UloziskoSk"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?ulozisko.sk/.*'
- __version__ = "0.23"
__description__ = """Ulozisko.sk hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
- URL_PATTERN = r'<form name = "formular" action = "([^"]+)" method = "post">'
+
+ 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 = "([^"]+)" />'
- 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 />'
- CAPTCHA_PATTERN = r'<img src="(/obrazky/obrazky.php\?fid=[^"]+)" alt="" />'
- FILE_OFFLINE_PATTERN = ur'<span class = "red">ZadanÜ súbor neexistuje z jedného z nasledujúcich dÎvodov:</span>'
+ CAPTCHA_PATTERN = r'<img src="(/obrazky/obrazky\.php\?fid=[^"]+)" alt="" />'
IMG_PATTERN = ur'<strong>PRE ZVÄČŠENIE KLIKNITE NA OBRÁZOK</strong><br /><a href = "([^"]+)">'
+
def process(self, pyfile):
self.html = self.load(pyfile.url, decode=True)
self.getFileInfo()
- found = re.search(self.IMG_PATTERN, self.html)
- if found:
- url = "http://ulozisko.sk" + found.group(1)
+ m = re.search(self.IMG_PATTERN, self.html)
+ if m:
+ url = "http://ulozisko.sk" + m.group(1)
self.download(url)
else:
self.handleFree()
+
def handleFree(self):
- found = re.search(self.URL_PATTERN, self.html)
- if found is None:
- raise PluginParseError('URL')
- parsed_url = 'http://www.ulozisko.sk' + found.group(1)
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ self.error(_("LINK_PATTERN not found"))
+ parsed_url = 'http://www.ulozisko.sk' + m.group(1)
- found = re.search(self.ID_PATTERN, self.html)
- if found is None:
- raise PluginParseError('ID')
- id = found.group(1)
+ m = re.search(self.ID_PATTERN, self.html)
+ if m is None:
+ self.error(_("ID_PATTERN not found"))
+ id = m.group(1)
- self.logDebug('URL:' + parsed_url + ' ID:' + id)
+ self.logDebug("URL:" + parsed_url + ' ID:' + id)
- found = re.search(self.CAPTCHA_PATTERN, self.html)
- if found is None:
- raise PluginParseError('CAPTCHA')
- captcha_url = 'http://www.ulozisko.sk' + found.group(1)
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
+ if m is None:
+ self.error(_("CAPTCHA_PATTERN not found"))
+ captcha_url = 'http://www.ulozisko.sk' + m.group(1)
captcha = self.decryptCaptcha(captcha_url, cookies=True)
- self.logDebug('CAPTCHA_URL:' + captcha_url + ' CAPTCHA:' + captcha)
+ self.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 1a64146c4..8c39cce82 100644
--- a/module/plugins/hoster/UnibytesCom.py
+++ b/module/plugins/hoster/UnibytesCom.py
@@ -1,53 +1,46 @@
# -*- 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
- @author: zoidberg
-"""
+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")]
+
- FILE_INFO_PATTERN = r'<span[^>]*?id="fileName"[^>]*>(?P<N>[^>]+)</span>\s*\((?P<S>\d.*?)\)'
- DOMAIN = 'http://www.unibytes.com'
+ HOSTER_DOMAIN = "unibytes.com"
+
+ INFO_PATTERN = r'<span[^>]*?id="fileName"[^>]*>(?P<N>[^>]+)</span>\s*\((?P<S>\d.*?)\)'
WAIT_PATTERN = r'Wait for <span id="slowRest">(\d+)</span> sec'
- DOWNLOAD_LINK_PATTERN = r'<a href="([^"]+)">Download</a>'
+ LINK_PATTERN = r'<a href="([^"]+)">Download</a>'
+
def handleFree(self):
+ 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(self.DOMAIN + action, post=post_data)
+ self.html = self.load(urljoin(domain, action), post=post_data)
- found = re.search(r'location:\s*(\S+)', self.req.http.header, re.I)
- if found:
- url = found.group(1)
+ m = re.search(r'location:\s*(\S+)', self.req.http.header, re.I)
+ if m:
+ url = m.group(1)
break
if '>Somebody else is already downloading using your IP-address<' in self.html:
@@ -55,9 +48,9 @@ class UnibytesCom(SimpleHoster):
self.retry()
if post_data['step'] == 'last':
- found = re.search(self.DOWNLOAD_LINK_PATTERN, self.html)
- if found:
- url = found.group(1)
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m:
+ url = m.group(1)
self.correctCaptcha()
break
else:
@@ -67,14 +60,13 @@ class UnibytesCom(SimpleHoster):
action, post_data = self.parseHtmlForm('id="stepForm"')
if last_step == 'timer':
- found = re.search(self.WAIT_PATTERN, self.html)
- self.wait(int(found.group(1)) if found else 60, False)
- elif last_step in ('captcha', 'last'):
- post_data['captcha'] = self.decryptCaptcha(self.DOMAIN + '/captcha.jpg')
+ 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(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 a0447d873..6e16cace7 100644
--- a/module/plugins/hoster/UnrestrictLi.py
+++ b/module/plugins/hoster/UnrestrictLi.py
@@ -1,100 +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():
- # Seconds until 00:10 GMT+2
- now = datetime.utcnow() + timedelta(hours=2)
- 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.11"
- __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.logInfo("Reached daily limit for this host. Waiting until 00:10 GMT+2")
- self.retry(5, secondsToMidnight(), "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 6d17bcbd9..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
@@ -54,17 +55,22 @@ def getAPIData(urls):
def parseFileInfo(self, url='', html=''):
if not html and hasattr(self, "html"):
html = self.html
- name, size, status, found, fileid = url, 0, 3, None, None
- if re.search(self.FILE_OFFLINE_PATTERN, html):
+ name = url
+ size = 0
+ fileid = None
+
+ if re.search(self.OFFLINE_PATTERN, html):
# File offline
status = 1
else:
- found = re.search(self.FILE_INFO_PATTERN, html)
- if found:
- name, fileid = html_unescape(found.group('N')), found.group('ID')
- size = parseFileSize(found.group('S'))
+ m = re.search(self.INFO_PATTERN, html)
+ if m:
+ name, fileid = html_unescape(m.group('N')), m.group('ID')
+ size = parseFileSize(m.group('S'))
status = 2
+ else:
+ status = 3
return name, size, status, fileid
@@ -86,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.72"
+
__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")]
+
+
+ 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'
- FILE_INFO_PATTERN = r'<a href="file/(?P<ID>\w+)" id="filename">(?P<N>[^<]+)</a> &nbsp;\s*<small[^>]*>(?P<S>[^<]+)</small>'
- FILE_OFFLINE_PATTERN = r'<small class="cL">Error: 404</small>'
- DL_LIMIT_PATTERN = "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)
@@ -114,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)
@@ -124,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"))
@@ -145,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__))
+ "left": info['trafficleft'] / 1024 / 1024})
+ if int(self.data[1]) / 1024 > info['trafficleft']:
+ 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)
- found = re.search(r'<div class="tfree".*\s*<form method="post" action="(.*?)"', self.html)
- if not found:
- self.fail("Download URL not found. Try to enable direct downloads.")
- url = found.group(1)
- print "Premium URL: " + url
+ 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"))
+ url = m.group(1)
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)
- found = re.search(r"Current waiting period: <span>(\d+)</span> seconds", self.html)
- if not found:
- self.fail("File not downloadable for free users")
- self.setWait(int(found.group(1)))
+ 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.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")
+ elif '"err":"captcha"' in result:
self.invalidCaptcha()
elif "type:'download'" in result:
self.correctCaptcha()
downloadURL = re.search("url:'([^']+)", result).group(1)
break
else:
- self.fail("Unknown error '%s'")
+ 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 6ee3dbeba..189079017 100644
--- a/module/plugins/hoster/UploadheroCom.py
+++ b/module/plugins/hoster/UploadheroCom.py
@@ -1,90 +1,81 @@
# -*- 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/>.
-
- @author: zoidberg
-"""
-
-# 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")]
+
- SH_COOKIES = [("http://uploadhero.co", "lang", "en")]
- FILE_NAME_PATTERN = r'<div class="nom_de_fichier">(?P<N>.*?)</div>'
- FILE_SIZE_PATTERN = r'Taille du fichier : </span><strong>(?P<S>.*?)</strong>'
- FILE_OFFLINE_PATTERN = r'<p class="titre_dl_2">|<div class="raison"><strong>Le lien du fichier ci-dessus n\'existe plus.'
+ 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.'
- DOWNLOAD_URL_PATTERN = r'<a href="([^"]+)" id="downloadnow"'
+ 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"'
+
def handleFree(self):
self.checkErrors()
- found = re.search(self.CAPTCHA_PATTERN, self.html)
- if not found:
- self.parseError("Captcha URL")
- captcha_url = "http://uploadhero.co" + found.group(1)
+ m = re.search(self.CAPTCHA_PATTERN, self.html)
+ if m is None:
+ self.error(_("CAPTCHA_PATTERN not found"))
+ captcha_url = "http://uploadhero.co" + m.group(1)
- for _ in xrange(5):
+ for _i in xrange(5):
captcha = self.decryptCaptcha(captcha_url)
self.html = self.load(self.pyfile.url, get={"code": captcha})
- found = re.search(self.FREE_URL_PATTERN, self.html)
- if found:
+ m = re.search(self.FREE_URL_PATTERN, self.html)
+ if m:
self.correctCaptcha()
- download_url = found.group(1) or found.group(2)
+ download_url = m.group(1) or m.group(2)
break
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.DOWNLOAD_URL_PATTERN, self.html).group(1)
- self.logDebug("Downloading link : '%s'" % link)
+ link = re.search(self.PREMIUM_URL_PATTERN, self.html).group(1)
self.download(link)
+
def checkErrors(self):
- found = re.search(self.IP_BLOCKED_PATTERN, self.html)
- if found:
- self.html = self.load("http://uploadhero.co%s" % found.group(1))
+ m = re.search(self.IP_BLOCKED_PATTERN, self.html)
+ if m:
+ self.html = self.load("http://uploadhero.co%s" % m.group(1))
- found = re.search(self.IP_WAIT_PATTERN, self.html)
- wait_time = (int(found.group(1)) * 60 + int(found.group(2))) if found else 5 * 60
+ m = re.search(self.IP_WAIT_PATTERN, self.html)
+ wait_time = (int(m.group(1)) * 60 + int(m.group(2))) if m else 5 * 60
self.wait(wait_time, True)
self.retry()
+ self.info.pop('error', None)
+
getInfo = create_getInfo(UploadheroCom)
diff --git a/module/plugins/hoster/UploadingCom.py b/module/plugins/hoster/UploadingCom.py
index f3cc7a1c6..b163f2252 100644
--- a/module/plugins/hoster/UploadingCom.py
+++ b/module/plugins/hoster/UploadingCom.py
@@ -1,63 +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/>.
-
- @author: jeix
-"""
-
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.34"
+ __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+)<'
- FILE_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)
@@ -66,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):
- found = re.search('<h2>((Daily )?Download Limit)</h2>', self.html)
- if found:
- self.pyfile.error = found.group(1)
+ 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 found.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.pluginParseError("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.pluginParseError("AJAX/URL")
+ self.error(_("No AJAX/URL"))
self.html = self.load(url)
- found = re.search(r'<form id="file_form" action="(.*?)"', self.html)
- if found:
- url = found.group(1)
+ m = re.search(r'<form id="file_form" action="(.*?)"', self.html)
+ if m:
+ url = m.group(1)
else:
- self.pluginParseError("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 9d1c4b3dd..25c424f1f 100644
--- a/module/plugins/hoster/UpstoreNet.py
+++ b/module/plugins/hoster/UpstoreNet.py
@@ -1,32 +1,38 @@
# -*- 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"
- __pattern__ = r"https?://(?:www\.)?upstore\.net/"
- __version__ = "0.02"
+ __name__ = "UpstoreNet"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
+ __pattern__ = r'https?://(?:www\.)?upstore\.net/'
+
__description__ = """Upstore.Net File Download Hoster"""
- __author_name__ = ("igel")
+ __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+)'
- FILE_OFFLINE_PATTERN = r'<span class="error">File not found</span>'
+ 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+)"
+ WAIT_PATTERN = r'var sec = (\d+)'
CHASH_PATTERN = r'<input type="hidden" name="hash" value="([^"]*)">'
- DIRECT_LINK_PATTERN = r'<a href="(https?://.*?)" target="_blank"><b>'
+ LINK_PATTERN = r'<a href="(https?://.*?)" target="_blank"><b>'
+
def handleFree(self):
# STAGE 1: get link to continue
m = re.search(self.CHASH_PATTERN, self.html)
- if not m:
- self.parseError("could not detect hash")
+ if m is None:
+ 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)
@@ -34,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 not m:
- self.parseError("could not find wait pattern")
- wait_time = m.group(1)
+ if m is None:
+ self.error(_("Wait pattern not found"))
+ wait_time = int(m.group(1))
# then, do the waiting
self.wait(wait_time)
# then, handle the captcha
- 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.DIRECT_LINK_PATTERN, self.html, re.DOTALL)
+ m = re.search(self.LINK_PATTERN, self.html, re.S)
if m:
break
- if not m:
- self.parseError("could not detect direct link")
+ if m is None:
+ 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 e403425c1..21d781f55 100644
--- a/module/plugins/hoster/UptoboxCom.py
+++ b/module/plugins/hoster/UptoboxCom.py
@@ -1,81 +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/>.
-#
-# @author: Walter Purcaro
-###############################################################################
-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_DOMAIN = "uptobox.com"
- HOSTER_NAME = "uptobox.com"
+ INFO_PATTERN = r'"para_title">(?P<N>.+) \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)'
+ OFFLINE_PATTERN = r'>(File not found|Access Denied|404 Not Found)'
- FILE_INFO_PATTERN = r'"para_title">(?P<N>.+) \((?P<S>[\d\.]+) (?P<U>\w+)\)'
- FILE_OFFLINE_PATTERN = r'>(File not found|Access Denied|404 Not Found)'
- TEMP_OFFLINE_PATTERN = r'>This server is in maintenance mode'
+ LINK_PATTERN = r'"(https?://\w+\.uptobox\.com/d/.*?)"'
- WAIT_PATTERN = r'>(\d+)</span> seconds<'
+ ERROR_PATTERN = r'>(You have to wait.+till next download.)<' #@TODO: Check XFSHoster ERROR_PATTERN
- DIRECT_LINK_PATTERN = r'"(https?://\w+\.uptobox\.com/d/.*?)"'
- def handleCaptcha(self, inputs):
- found = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if found:
- captcha_key = found.group(1)
- captcha = SolveMedia(self)
- inputs['adcopy_challenge'], inputs['adcopy_response'] = captcha.challenge(captcha_key)
- return 4
- else:
- found = re.search(self.CAPTCHA_URL_PATTERN, self.html)
- if found:
- captcha_url = found.group(1)
- inputs['code'] = self.decryptCaptcha(captcha_url)
- return 2
- else:
- found = re.search(self.CAPTCHA_DIV_PATTERN, self.html, re.DOTALL)
- if found:
- captcha_div = found.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:
- found = re.search(self.RECAPTCHA_URL_PATTERN, self.html)
- if found:
- recaptcha_key = unquote(found.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
+ 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 22fc4b207..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,48 +32,50 @@ 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 self.html is None:
+ if not self.html:
self.download_html()
if '<title>Veehd</title>' in self.html:
return False
return True
+
def get_file_name(self):
- if self.html is None:
+ if not self.html:
self.download_html()
- match = re.search(r'<title[^>]*>([^<]+) on Veehd</title>', self.html)
- if not match:
- self.fail("video title not found")
- name = match.group(1)
+ m = re.search(r'<title[^>]*>([^<]+) on Veehd</title>', self.html)
+ if m is None:
+ 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'
- name = re.sub(pattern, self.getConfig('replacement_char'),
- name)
- return name + '.avi'
def get_file_url(self):
""" returns the absolute downloadable filepath
"""
- if self.html is None:
+ if not self.html:
self.download_html()
- match = re.search(r'<embed type="video/divx" src="(http://([^/]*\.)?veehd\.com/dl/[^"]+)"',
+ m = re.search(r'<embed type="video/divx" src="(http://([^/]*\.)?veehd\.com/dl/[^"]+)"',
self.html)
- if not match:
- self.fail("embedded video url not found")
- file_url = match.group(1)
+ if m is None:
+ self.error(_("Embedded video url not found"))
- return file_url
+ return m.group(1)
diff --git a/module/plugins/hoster/VeohCom.py b/module/plugins/hoster/VeohCom.py
index c1ebffb81..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,37 +6,48 @@ 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.1"
- __config__ = [("quality", "Low;High", "Quality", "High")]
+ __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>.*?)"'
- FILE_OFFLINE_PATTERN = r'>Sorry, we couldn\'t find the video you were looking for'
+ 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):
- q = self.getConfig("quality")
- pattern = r'"fullPreviewHash%sPath":"(.+?)"' % q
- found = re.search(pattern, self.html)
- if found:
- self.pyfile.name += ".mp4"
- link = found.group(1).replace("\\", "")
- self.logDebug("Download link: " + link)
- self.download(link)
+ quality = self.getConfig("quality")
+ if quality == "Auto":
+ quality = ("High", "Low")
+ for q in quality:
+ pattern = r'"fullPreviewHash%sPath":"(.+?)"' % q
+ m = re.search(pattern, self.html)
+ if m:
+ self.pyfile.name += ".mp4"
+ link = m.group(1).replace("\\", "")
+ self.download(link)
+ return
+ else:
+ self.logInfo(_("No %s quality video found") % q.upper())
else:
- self.fail("No %s quality video found" % q.lower())
+ self.fail(_("No video found!"))
getInfo = create_getInfo(VeohCom)
diff --git a/module/plugins/hoster/VidPlayNet.py b/module/plugins/hoster/VidPlayNet.py
index ade416750..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"
- FILE_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]>'
- DIRECT_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
new file mode 100644
index 000000000..0e42c1674
--- /dev/null
+++ b/module/plugins/hoster/VimeoCom.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class VimeoCom(SimpleHoster):
+ __name__ = "VimeoCom"
+ __type__ = "hoster"
+ __version__ = "0.03"
+
+ __pattern__ = r'https?://(?:www\.)?(player\.)?vimeo\.com/(video/)?(?P<ID>\d+)'
+ __config__ = [("quality", "Lowest;Mobile;SD;HD;Highest", "Quality", "Highest"),
+ ("original", "bool", "Try to download the original file first", True)]
+
+ __description__ = """Vimeo.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ NAME_PATTERN = r'<title>(?P<N>.+) on Vimeo<'
+ OFFLINE_PATTERN = r'class="exception_header"'
+ TEMP_OFFLINE_PATTERN = r'Please try again in a few minutes.<'
+
+ URL_REPLACEMENTS = [(__pattern__ + ".*", r'https://www.vimeo.com/\g<ID>')]
+
+ COOKIES = [("vimeo.com", "language", "en")]
+
+
+ def setup(self):
+ self.resumeDownload = True
+ self.multiDL = True
+ self.chunkLimit = -1
+
+
+ def handleFree(self):
+ 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", '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, get={'password': password})
+ pattern = r'"(?P<QL>\w+)":{"profile".*?"(?P<URL>http://pdl\.vimeocdn\.com.+?)"'
+
+ link = dict([(l.group('QL').lower(), l.group('URL')) for l in re.finditer(pattern, html)])
+
+ if self.getConfig("original"):
+ if "original" in link:
+ self.download(link[q])
+ return
+ else:
+ self.logInfo(_("Original file not downloadable"))
+
+ quality = self.getConfig("quality")
+ if quality == "Highest":
+ qlevel = ("hd", "sd", "mobile")
+ elif quality == "Lowest":
+ qlevel = ("mobile", "sd", "hd")
+ else:
+ qlevel = quality.lower()
+
+ for q in qlevel:
+ if q in link:
+ self.download(link[q])
+ return
+ else:
+ self.logInfo(_("No %s quality video found") % q.upper())
+ else:
+ self.fail(_("No video found!"))
+
+
+getInfo = create_getInfo(VimeoCom)
diff --git a/module/plugins/hoster/Vipleech4uCom.py b/module/plugins/hoster/Vipleech4uCom.py
index 53768a430..340a3feaa 100644
--- a/module/plugins/hoster/Vipleech4uCom.py
+++ b/module/plugins/hoster/Vipleech4uCom.py
@@ -1,84 +1,18 @@
# -*- coding: utf-8 -*-
-import re
+from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo
-from module.plugins.Hoster import Hoster
+class Vipleech4uCom(DeadHoster):
+ __name__ = "Vipleech4uCom"
+ __type__ = "hoster"
+ __version__ = "0.20"
-class Vipleech4uCom(Hoster):
- __name__ = "Vipleech4uCom"
- __version__ = "0.1"
- __type__ = "hoster"
- __pattern__ = r"http://vipleech4u.com/manager.php"
- __description__ = """Vipleech4u.com hoster plugin"""
- __author_name__ = ("Kagenoshin")
- __author_mail__ = ("kagenoshin@gmx.ch")
-
- FILENAME_PATTERN = re.compile(r'name\s*?=\s*?["\']filename["\'][^>]*?value\s*?=\s*?["\'](.*?)["\']', re.I)
- HOST_PATTERN = re.compile(r'name\s*?=\s*?["\']host["\'][^>]*?value\s*?=\s*?["\'](.*?)["\']', re.I)
- PATH_PATTERN = re.compile(r'name\s*?=\s*?["\']path["\'][^>]*?value\s*?=\s*?["\'](.*?)["\']', re.I)
- REFERER_PATTERN = re.compile(r'name\s*?=\s*?["\']referer["\'][^>]*?value\s*?=\s*?["\'](.*?)["\']', re.I)
- LINK_PATTERN = re.compile(r'name\s*?=\s*?["\']link["\'][^>]*?value\s*?=\s*?["\'](.*?)["\']', re.I)
- COOKIE_PATTERN = re.compile(r'name\s*?=\s*?["\']cookie["\'][^>]*?value\s*?=\s*?["\'](.*?)["\']', re.I)
-
- 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") % "vipleech4u.com")
- self.fail("No vipleech4u.com account provided")
-
- self.logDebug("Old URL: %s" % pyfile.url)
-
- new_url = pyfile.url
-
- if re.match(self.__pattern__, new_url):
- self.fail("Can't handle vipleech4u links.")
-
- #upload the link which has to be loaded
- page = self.load('http://vipleech4u.com/generator.php', post={'links': new_url, 'ddl': 'no'})
+ __pattern__ = r'http://(?:www\.)?vipleech4u\.com/manager\.php'
- #switch to the manager and see what's happening
- page = self.load('http://vipleech4u.com/unrestrict.php', get={'link': new_url, 'premium_acc': 'on'})
-
- if re.search(r'You have generated maximum links available to you today', page, re.I):
- self.fail('Daily limit reached.')
-
- filename = self.FILENAME_PATTERN.search(page)
- host = self.HOST_PATTERN.search(page)
- path = self.PATH_PATTERN.search(page)
- referer = self.REFERER_PATTERN.search(page)
- link = self.LINK_PATTERN.search(page)
- cookie = self.COOKIE_PATTERN.search(page)
-
- #build the post-dictionary
- post_dict = {}
-
- if filename:
- post_dict.update({'filename': filename.group(1)})
- if host:
- post_dict.update({'host': host.group(1)})
- if path:
- post_dict.update({'path': path.group(1)})
- if referer:
- post_dict.update({'referer': referer.group(1)})
- if link:
- post_dict.update({'link': link.group(1)})
- if cookie:
- post_dict.update({'cookie': cookie.group(1)})
-
- if not post_dict:
- self.logDebug('Get an empty post_dict. Strange.')
-
- self.setWait(5)
- self.wait()
- self.logDebug("Unrestricted URL: " + str(post_dict))
-
- self.download('http://vipleech4u.com/unrestrict.php', post=post_dict, disposition=True)
+ __description__ = """Vipleech4u.com hoster plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")]
- check = self.checkDownload({"bad": "<html"})
- if check == "bad":
- self.retry(24, 150, 'Bad file downloaded')
+getInfo = create_getInfo(Vipleech4uCom)
diff --git a/module/plugins/hoster/WarserverCz.py b/module/plugins/hoster/WarserverCz.py
index a80349b45..c83d5c03e 100644
--- a/module/plugins/hoster/WarserverCz.py
+++ b/module/plugins/hoster/WarserverCz.py
@@ -1,77 +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 WarserverCz(DeadHoster):
+ __name__ = "WarserverCz"
+ __type__ = "hoster"
+ __version__ = "0.13"
- @author: zoidberg
-"""
+ __pattern__ = r'http://(?:www\.)?warserver\.cz/stahnout/\d+'
-#similar to coolshare.cz (down)
-
-import re
-from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
-from module.network.HTTPRequest import BadHeader
-from module.utils import html_unescape
-
-
-class WarserverCz(SimpleHoster):
- __name__ = "WarserverCz"
- __type__ = "hoster"
- __pattern__ = r'http://(?:www\.)?warserver.cz/stahnout/(?P<ID>\d+)/.+'
- __version__ = "0.12"
__description__ = """Warserver.cz hoster plugin"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
-
- FILE_NAME_PATTERN = r'<h1.*?>(?P<N>[^<]+)</h1>'
- FILE_SIZE_PATTERN = r'<li>Velikost: <strong>(?P<S>[^<]+)</strong>'
- FILE_OFFLINE_PATTERN = r'<h1>Soubor nenalezen</h1>'
-
- PREMIUM_URL_PATTERN = r'href="(http://[^/]+/dwn-premium.php.*?)"'
- DOMAIN = "http://csd01.coolshare.cz"
-
- DOMAIN = "http://s01.warserver.cz"
-
- def handleFree(self):
- try:
- self.download("%s/dwn-free.php?fid=%s" % (self.DOMAIN, self.file_info['ID']))
- except BadHeader, e:
- self.logError(e)
- if e.code == 403:
- self.longWait(60, 60)
- else:
- raise
- self.checkDownloadedFile()
-
- def handlePremium(self):
- found = re.search(self.PREMIUM_URL_PATTERN, self.html)
- if not found:
- self.parseError("Premium URL")
- url = html_unescape(found.group(1))
- self.logDebug("Premium URL: " + url)
- if not url.startswith("http://"):
- self.resetAccount()
- self.download(url)
- self.checkDownloadedFile()
-
- def checkDownloadedFile(self):
- check = self.checkDownload({
- "offline": ">404 Not Found<"
- })
-
- if check == "offline":
- self.offline()
+ __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 53dc3b95c..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 not m:
- self.parseError('Unable to detect direct link')
- direct = m.group(1)
- self.logDebug("Direct link: " + direct)
- self.download(direct, disposition=True)
+ if m is None:
+ 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 7966b980a..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/>.
-
- @author: zoidberg
-"""
-
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")]
+
+
+ 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")]
- SH_COOKIES = [("http://www.wrzuc.to", "language", "en")]
- FILE_SIZE_PATTERN = r'class="info">\s*<tr>\s*<td>(?P<S>.*?)</td>'
- FILE_NAME_PATTERN = r'id="file_info">\s*<strong>(?P<N>.*?)</strong>'
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 f69283c47..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/>.
-#
-# @author: zoidberg
-###############################################################################
-
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_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>'
- FILE_INFO_PATTERN = r'<tr><td align=right><b>Filename:</b></td><td nowrap>(?P<N>[^<]+)</td></tr>\s*.*?<small>\((?P<S>[^<]+)\)</small>'
- FILE_OFFLINE_PATTERN = r'>\w+ (Not Found|file (was|has been) removed)'
-
- WAIT_PATTERN = r'<span id="countdown_str">.*?>(\d+)</span>'
- #LONG_WAIT_PATTERN = r'(?P<H>\d+(?=\s*hour))?.*?(?P<M>\d+(?=\s*minute))?.*?(?P<S>\d+(?=\s*second))?'
- OVR_DOWNLOAD_LINK_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)'
- OVR_KILL_LINK_PATTERN = r'<h2>Delete 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, "DIRECT_LINK_PATTERN"):
- self.DIRECT_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)
-
- location = None
- found = re.search(r"Location\s*:\s*(.*)", self.header, re.I)
- if found and re.match(self.DIRECT_LINK_PATTERN, found.group(1)):
- location = found.group(1).strip()
- return location
+from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo
- 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()
+class XFileSharingPro(XFSHoster):
+ __name__ = "XFileSharingPro"
+ __type__ = "hoster"
+ __version__ = "0.43"
- 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)
-
- found = re.search(r"Location\s*:\s*(.*)", self.header, re.I)
- if found:
- break
-
- found = re.search(self.DIRECT_LINK_PATTERN, self.html, re.S)
- if found:
- 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 found.group(1)
- def handlePremium(self):
- self.html = self.load(self.pyfile.url, post=self.getPostParameters())
- found = re.search(self.DIRECT_LINK_PATTERN, self.html)
- if not found:
- self.parseError('DIRECT LINK')
- self.startDownload(found.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
- found = re.search(self.OVR_DOWNLOAD_LINK_PATTERN, self.html)
- if not found:
- self.parseError('DIRECT LINK (OVR)')
- self.pyfile.url = found.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):
- found = re.search(self.ERROR_PATTERN, self.html)
- if found:
- self.errmsg = found.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")
-
- self.logDebug(self.HOSTER_NAME, inputs)
+ return
- 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")
+ self.user, data = self.account.selectAccount()
+ self.req = self.account.getAccountRequest(self.user)
+ self.premium = self.account.isPremium(self.user)
- if not self.premium:
- found = re.search(self.WAIT_PATTERN, self.html)
- if found:
- wait_time = int(found.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):
- found = re.search(self.RECAPTCHA_URL_PATTERN, self.html)
- if found:
- recaptcha_key = unquote(found.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:
- found = re.search(self.CAPTCHA_URL_PATTERN, self.html)
- if found:
- captcha_url = found.group(1)
- inputs['code'] = self.decryptCaptcha(captcha_url)
- return 2
- else:
- found = re.search(self.CAPTCHA_DIV_PATTERN, self.html, re.DOTALL)
- if found:
- captcha_div = found.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:
- found = re.search(self.SOLVEMEDIA_PATTERN, self.html)
- if found:
- captcha_key = found.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 0f0371f21..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,81 +41,87 @@ 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 self.html is None:
+ 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 json_flashvar is None:
- self.fail("Parse error (flashvars)")
+ if not json_flashvar:
+ self.error(_("flashvar not found"))
j = clean_json(json_flashvar.group(1))
flashvars = json_loads(j)
- if flashvars["srv"]:
- srv_url = flashvars["srv"] + '/'
+ 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']
+
- 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"])
+ 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 self.html is None:
+ if not self.html:
self.download_html()
- file_name_pattern = r"<title>(.*?) - xHamster\.com</title>"
- file_name = re.search(file_name_pattern, self.html)
- if file_name is None:
- file_name_pattern = r"<h1 >(.*)</h1>"
- file_name = re.search(file_name_pattern, self.html)
- if file_name is None:
- file_name_pattern = r"http://[www.]+xhamster\.com/movies/.*/(.*?)\.html?"
- file_name = re.match(file_name_pattern, self.pyfile.url)
- if file_name is None:
- file_name_pattern = r"<div id=\"element_str_id\" style=\"display:none;\">(.*)</div>"
- file_name = re.search(file_name_pattern, self.html)
- if file_name is None:
+ pattern = r'<title>(.*?) - xHamster\.com</title>'
+ name = re.search(pattern, self.html)
+ if name is None:
+ pattern = r'<h1 >(.*)</h1>'
+ name = re.search(pattern, self.html)
+ if name is None:
+ 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>'
+ name = re.search(pattern, self.html)
+ if name is None:
return "Unknown"
- return file_name.group(1)
+ return name.group(1)
+
def file_exists(self):
""" returns True or False
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if re.search(r"(.*Video not found.*)", self.html) is not None:
return False
diff --git a/module/plugins/hoster/XVideosCom.py b/module/plugins/hoster/XVideosCom.py
index b2fa5243f..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__ = ""
- __author_mail__ = ""
+ __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 53f61836b..ef6da4a71 100644
--- a/module/plugins/hoster/Xdcc.py
+++ b/module/plugins/hoster/Xdcc.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/>.
-
- @author: jeix
-"""
-
-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"):
@@ -64,24 +50,20 @@ class Xdcc(Hoster):
else:
errno = e.args[0]
- if errno in (10054,):
- self.logDebug("XDCC: Server blocked our ip, retry in 5 min")
+ if errno == 10054:
+ 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)
@@ -98,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
@@ -135,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]:
@@ -155,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,31 +150,31 @@ class Xdcc(Hoster):
"text": msg[3][1:]
}
- if nick == msg["target"][0:len(nick)] and "PRIVMSG" == msg["action"]:
- if msg["text"] == "\x01VERSION\x01":
- self.logDebug("XDCC: Sending CTCP VERSION.")
+ if nick == msg['target'][0:len(nick)] and "PRIVMSG" == msg['action']:
+ if msg['text'] == "\x01VERSION\x01":
+ 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.")
+ elif msg['text'] == "\x01TIME\x01":
+ self.logDebug("Sending CTCP TIME")
sock.send("NOTICE %s :%d\r\n" % (msg['origin'], time.time()))
- elif msg["text"] == "\x01LAG\x01":
+ elif msg['text'] == "\x01LAG\x01":
pass # don't know how to answer
- if not (bot == msg["origin"][0:len(bot)]
- and nick == msg["target"][0:len(nick)]
- and msg["action"] in ("PRIVMSG", "NOTICE")):
+ if not (bot == msg['origin'][0:len(bot)]
+ and nick == msg['target'][0:len(nick)]
+ and msg['action'] in ("PRIVMSG", "NOTICE")):
continue
if self.debug is 1:
- print "%s: %s" % (msg["origin"], msg["text"])
+ print "%s: %s" % (msg['origin'], msg['text'])
- if "You already requested that pack" in msg["text"]:
+ if "You already requested that pack" in msg['text']:
retry = time.time() + 300
- if "you must be on a known channel to request a pack" in msg["text"]:
- self.fail("Wrong channel")
+ if "you must be on a known channel to request a pack" in msg['text']:
+ self.fail(_("Wrong channel"))
- m = re.match('\x01DCC SEND (.*?) (\d+) (\d+)(?: (\d+))?\x01', msg["text"])
+ m = re.match('\x01DCC SEND (.*?) (\d+) (\d+)(?: (\d+))?\x01', msg['text'])
if m:
done = True
@@ -205,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 e51937924..3b4692933 100644
--- a/module/plugins/hoster/YibaishiwuCom.py
+++ b/module/plugins/hoster/YibaishiwuCom.py
@@ -1,60 +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/>.
-
- @author: zoidberg
-"""
-
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>[^']+)'"
- FILE_OFFLINE_PATTERN = ur'<h3><i style="color:red;">哎呀提取码䞍存圚䞍劚搜搜看吧</i></h3>'
+ 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)[^"\']+)'
- AJAX_URL_PATTERN = r'(/\?ct=(pickcode|download)[^"\']+)'
def handleFree(self):
- found = re.search(self.AJAX_URL_PATTERN, self.html)
- if not found:
- self.parseError("AJAX URL")
- url = found.group(1)
- self.logDebug(('FREEUSER' if found.group(2) == 'download' else 'GUEST') + ' URL', url)
-
- response = json_loads(self.load("http://115.com" + url, decode=False))
- for mirror in (response['urls'] if 'urls' in response else response['data'] if 'data' in response else []):
+ m = re.search(self.LINK_PATTERN, self.html)
+ if m is None:
+ self.error(_("LINK_PATTERN not found"))
+ url = m.group(1)
+ self.logDebug(('FREEUSER' if m.group(2) == 'download' else 'GUEST') + ' URL', url)
+
+ res = json_loads(self.load("http://115.com" + url, decode=False))
+ if "urls" in res:
+ mirrors = res['urls']
+ elif "data" in res:
+ mirrors = res['data']
+ else:
+ mirrors = None
+
+ for mr in mirrors:
try:
- url = mirror['url'].replace('\\', '')
+ url = mr['url'].replace("\\", "")
self.logDebug("Trying URL: " + url)
self.download(url)
break
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 9dc1dc6e9..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,30 +26,33 @@ 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
"""
- if self.html is None:
+ if not self.html:
self.download_html()
- file_url = re.search(r'(http://download\.youporn\.com/download/\d+\?save=1)">', self.html).group(1)
- return file_url
+ return re.search(r'(http://download\.youporn\.com/download/\d+\?save=1)">', self.html).group(1)
+
def get_file_name(self):
- if self.html is None:
+ 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
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if re.search(r"(.*invalid video_id.*)", self.html) is not None:
return False
diff --git a/module/plugins/hoster/YourfilesTo.py b/module/plugins/hoster/YourfilesTo.py
index c8c5c523c..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,11 +34,11 @@ 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 self.html is None:
+ if not self.html:
self.download_html()
#var zzipitime = 15;
@@ -43,31 +50,35 @@ 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 self.html is None:
+ if not self.html:
self.download_html()
return re.search("<title>(.*)</title>", self.html).group(1)
+
def file_exists(self):
""" returns True or False
"""
- if self.html is None:
+ if not self.html:
self.download_html()
if re.search(r"HTTP Status 404", self.html) is not None:
diff --git a/module/plugins/hoster/YoutubeCom.py b/module/plugins/hoster/YoutubeCom.py
index 330aae190..90c6df3c2 100644
--- a/module/plugins/hoster/YoutubeCom.py
+++ b/module/plugins/hoster/YoutubeCom.py
@@ -1,12 +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):
@@ -18,11 +20,12 @@ 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
else:
- for path in os.environ["PATH"].split(os.pathsep):
+ for path in os.environ['PATH'].split(os.pathsep):
path = path.strip('"')
exe_file = os.path.join(path, program)
if is_exe(exe_file):
@@ -32,10 +35,11 @@ def which(program):
class YoutubeCom(Hoster):
- __name__ = "YoutubeCom"
- __type__ = "hoster"
- __pattern__ = r'https?://(?:[^/]*\.)?youtube\.com/watch.*?[?&]v=.*'
- __version__ = "0.39"
+ __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),
@@ -43,37 +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")]
+
+
+ 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.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):
@@ -92,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)
@@ -109,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" %
@@ -138,6 +154,8 @@ class YoutubeCom(Hoster):
# Cleaning invalid characters from the file name
name = name.encode('ascii', 'replace')
+ for c in self.invalidChars:
+ name = name.replace(c, '_')
pyfile.name = html_unescape(name)
@@ -145,7 +163,7 @@ class YoutubeCom(Hoster):
ffmpeg = which("ffmpeg")
if ffmpeg and time:
m, s = time.groups()[1:]
- if not m:
+ if m is None:
m = "0"
pyfile.name += " (starting at %s:%s)" % (m, s)
diff --git a/module/plugins/hoster/ZDF.py b/module/plugins/hoster/ZDF.py
index e718f283e..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__ = ""
- __author_mail__ = ""
+ __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 b4fa4f8ac..67b384c5f 100644
--- a/module/plugins/hoster/ZippyshareCom.py
+++ b/module/plugins/hoster/ZippyshareCom.py
@@ -1,71 +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")]
+
+
+ NAME_PATTERN = r'("\d{6,}/"[ ]*\+.+?"/|<title>Zippyshare.com - )(?P<N>.+?)("|</title>)'
+ SIZE_PATTERN = r'>Size:.+?">(?P<S>[\d.,]+) (?P<U>[\w^_]+)'
- 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>[^"]+)";'
- FILE_OFFLINE_PATTERN = r'>File does not exist on this server</div>'
+ OFFLINE_PATTERN = r'>File does not exist on this server<'
+
+ COOKIES = [("zippyshare.com", "ziplocale", "en")]
- SH_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 not m:
- 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 400484d26..965799e8e 100644
--- a/module/plugins/internal/CaptchaService.py
+++ b/module/plugins/internal/CaptchaService.py
@@ -1,106 +1,332 @@
# -*- 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 random import random
- @author: zoidberg
-"""
+from module.common.json_layer import json_loads
-import re
-from random import random
+class CaptchaService:
+ __name__ = "CaptchaService"
+ __version__ = "0.16"
-class CaptchaService():
- __version__ = "0.04"
+ __description__ = """Base captcha service plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
- def __init__(self, plugin):
- self.plugin = plugin
+ KEY_PATTERN = None
-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 = None #: last key detected
- recaptcha_key = None
def __init__(self, plugin):
self.plugin = plugin
- def detect_key(self, html):
- m = re.search(self.RECAPTCHA_KEY_PATTERN, html)
- if not m:
- 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 not key and self.recaptcha_key:
- key = self.recaptcha_key
- elif not (key or self.recaptcha_key):
- raise TypeError("ReCaptcha key not found")
+ raise NotImplementedError
+
- js = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={"k": key}, cookies=True)
+ 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:
+ self.plugin.logDebug("ReCaptcha key not found")
+ return None
+
+ def challenge(self, key=None):
+ if not key:
+ if self.detect_key():
+ key = self.key
+ else:
+ errmsg = _("ReCaptcha key not found")
+ self.plugin.fail(errmsg)
+ raise TypeError(errmsg)
+
+ html = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={'k': key})
try:
- challenge = re.search("challenge : '(.*?)',", 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):
- def challenge(self, src):
- js = self.plugin.req.load(src, cookies=True)
+ __name__ = "AdsCaptcha"
+ __version__ = "0.06"
+
+ __description__ = """AdsCaptcha captcha service plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
+
+
+ CAPTCHAID_PATTERN = r'api\.adscaptcha\.com/Get\.aspx\?[^"\']*CaptchaId=(\d+)'
+ PUBLICKEY_PATTERN = r'api\.adscaptcha\.com/Get\.aspx\?[^"\']*PublicKey=([\w-]+)'
+
+ def detect_key(self, html=None):
+ if not html:
+ if hasattr(self.plugin, "html") and self.plugin.html:
+ html = self.plugin.html
+ else:
+ errmsg = _("AdsCaptcha html not found")
+ self.plugin.fail(errmsg)
+ raise TypeError(errmsg)
+
+ m = re.search(self.PUBLICKEY_PATTERN, html)
+ n = re.search(self.CAPTCHAID_PATTERN, html)
+ if m and n:
+ self.key = (m.group(1).strip(), n.group(1).strip()) #: key is the tuple(PublicKey, CaptchaId)
+ self.plugin.logDebug("AdsCaptcha key|id: %s | %s" % self.key)
+ return self.key
+ else:
+ self.plugin.logDebug("AdsCaptcha key or id not found")
+ return None
+
+
+ def challenge(self, key=None):
+ if not key:
+ if self.detect_key():
+ key = self.key
+ else:
+ errmsg = _("AdsCaptcha key not found")
+ self.plugin.fail(errmsg)
+ raise TypeError(errmsg)
+
+ PublicKey, CaptchaId = key
+
+ html = self.plugin.req.load("http://api.adscaptcha.com/Get.aspx", get={'CaptchaId': CaptchaId, 'PublicKey': PublicKey})
try:
- challenge = re.search("challenge: '(.*?)',", 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):
- def __init__(self, plugin):
- self.plugin = plugin
+ __name__ = "SolveMedia"
+ __version__ = "0.06"
+
+ __description__ = """SolveMedia captcha service plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("pyLoad Team", "admin@pyload.org")]
+
+
+ KEY_PATTERN = r'api\.solvemedia\.com/papi/challenge\.(?:no)?script\?k=(.+?)["\']'
- def challenge(self, src):
- html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.noscript?k=%s" % src, cookies=True)
+
+ 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:
- self.plugin.fail("solvemedia error")
- result = self.result(challenge)
+ 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:
+ 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 10eccb9bd..07c5c3881 100644
--- a/module/plugins/internal/DeadCrypter.py
+++ b/module/plugins/internal/DeadCrypter.py
@@ -1,16 +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"
- __type__ = "crypter"
- __pattern__ = None
- __version__ = "0.01"
- __description__ = """Crypter is no longer available"""
- __author_name__ = "stickell"
- __author_mail__ = "l.stickell@yahoo.it"
+ __name__ = "DeadCrypter"
+ __type__ = "crypter"
+ __version__ = "0.04"
+
+ __pattern__ = r'^unmatchable$'
+
+ __description__ = """ Crypter is no longer available """
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it")]
+
+
+ @classmethod
+ def 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 201835e2b..6f3252f70 100644
--- a/module/plugins/internal/DeadHoster.py
+++ b/module/plugins/internal/DeadHoster.py
@@ -1,22 +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):
- def getInfo(urls):
- yield [('#N/A: ' + url, 0, 1, url) for url in urls]
- return getInfo
+class DeadHoster(_Hoster):
+ __name__ = "DeadHoster"
+ __type__ = "hoster"
+ __version__ = "0.14"
+
+ __pattern__ = r'^unmatchable$'
+ __description__ = """ Hoster is no longer available """
+ __license__ = "GPLv3"
+ __authors__ = [("zoidberg", "zoidberg@mujmail.cz")]
+
+
+ @classmethod
+ def getInfo(cls, url="", html=""):
+ return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url}
-class DeadHoster(_Hoster):
- __name__ = "DeadHoster"
- __type__ = "hoster"
- __pattern__ = None
- __version__ = "0.11"
- __description__ = """Hoster is no longer available"""
- __author_name__ = "zoidberg"
- __author_mail__ = "zoidberg@mujmail.cz"
def setup(self):
- self.fail("Hoster is no longer available")
+ self.pyfile.error = "Hoster is no longer available"
+ self.offline() #@TODO: self.offline("Hoster is no longer available")
+
+
+getInfo = create_getInfo(DeadHoster)
diff --git a/module/plugins/internal/AbstractExtractor.py b/module/plugins/internal/Extractor.py
index 0ecc11f06..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,30 +8,52 @@ class CRCError(Exception):
pass
-class WrongPassword(Exception):
+class PasswordError(Exception):
pass
-class AbtractExtractor:
+class Extractor:
+ __name__ = "Extractor"
+ __version__ = "0.13"
+
+ __description__ = """Base extractor plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("RaNaN", "ranan@pyload.org"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
+ EXTENSIONS = []
- __version__ = "0.1"
- @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
@@ -42,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.
@@ -92,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 97f3a5996..9d218c3b2 100644
--- a/module/plugins/internal/MultiHoster.py
+++ b/module/plugins/internal/MultiHoster.py
@@ -2,188 +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):
- """
- Generic MultiHoster plugin
- """
+class MultiHoster(SimpleHoster):
+ __name__ = "MultiHoster"
+ __type__ = "hoster"
+ __version__ = "0.26"
- __version__ = "0.19"
+ __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 b1a18f5e0..428826456 100644
--- a/module/plugins/internal/SimpleCrypter.py
+++ b/module/plugins/internal/SimpleCrypter.py
@@ -1,78 +1,142 @@
# -*- 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.
+import re
- 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.
+from urlparse import urlparse
- 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.Crypter import Crypter
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns, set_cookies
+from module.utils import fixup
- @author: zoidberg
-"""
-import re
-
-from module.plugins.Crypter import Crypter
-from module.utils import html_unescape
-from module.plugins.internal.SimpleHoster import replace_patterns
+class SimpleCrypter(Crypter, SimpleHoster):
+ __name__ = "SimpleCrypter"
+ __type__ = "crypter"
+ __version__ = "0.35"
+ __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)]
-class SimpleCrypter(Crypter):
- __name__ = "SimpleCrypter"
- __version__ = "0.07"
- __pattern__ = None
- __type__ = "crypter"
__description__ = """Simple decrypter plugin"""
- __author_name__ = ("stickell", "zoidberg")
- __author_mail__ = ("l.stickell@yahoo.it", "zoidberg@mujmail.cz")
+ __license__ = "GPLv3"
+ __authors__ = [("stickell", "l.stickell@yahoo.it"),
+ ("zoidberg", "zoidberg@mujmail.cz"),
+ ("Walter Purcaro", "vuolter@gmail.com")]
+
+
"""
- These patterns should be defined by each crypter:
+ Following patterns should be defined by each crypter:
+
+ LINK_PATTERN: Download link or regex to catch links in group(1)
+ example: LINK_PATTERN = r'<div class="link"><a href="(.+?)"'
+
+ NAME_PATTERN: (optional) folder name or page title
+ example: NAME_PATTERN = r'<title>Files of: (?P<N>[^<]+) folder</title>'
+
+ OFFLINE_PATTERN: (optional) Checks if the page is unreachable
+ example: OFFLINE_PATTERN = r'File (deleted|not found)'
- LINK_PATTERN: group(1) must be a download link
- example: <div class="link"><a href="(http://speedload.org/\w+)
+ TEMP_OFFLINE_PATTERN: (optional) Checks if the page is temporarily unreachable
+ example: TEMP_OFFLINE_PATTERN = r'Server maintainance'
- TITLE_PATTERN: (optional) the group defined by 'title' should be the title
- example: <title>Files of: (?P<title>[^<]+) folder</title>
- 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 disposed on multiple pages you need to define a pattern:
- PAGES_PATTERN: the group defined by 'pages' must be the total number of pages
+ If the links are splitted on multiple pages you can define the PAGES_PATTERN regex:
- and a function:
+ PAGES_PATTERN: (optional) group(1) should be the number of overall pages containing the links
+ example: PAGES_PATTERN = r'Pages: (\d+)'
- loadPage(self, page_n):
- must return the html of the page number 'page_n'
+ and its loadPage method:
+
+
+ def loadPage(self, page_n):
+ return the html of the page number page_n
"""
- FILE_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
+
+ if self.LOGIN_PREMIUM and not self.premium:
+ self.fail(_("Required premium account not found"))
+
+ if self.LOGIN_ACCOUNT and not self.account:
+ self.fail(_("Required account not found"))
+
+ self.req.setOption("timeout", 120)
+
+ if isinstance(self.COOKIES, list):
+ set_cookies(self.req.cj, self.COOKIES)
+
+ self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS)
+
def decrypt(self, pyfile):
- pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS)
+ self.prepare()
+
+ self.preload()
- self.html = self.load(pyfile.url, decode=True)
+ 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.package_links:
- self.packages = [(package_name, self.package_links, folder_name)]
+ 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))
+
+ 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):
"""
@@ -81,26 +145,14 @@ class SimpleCrypter(Crypter):
"""
return re.findall(self.LINK_PATTERN, self.html)
- 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()
+ 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 f10433e78..d9732d063 100644
--- a/module/plugins/internal/SimpleHoster.py
+++ b/module/plugins/internal/SimpleHoster.py
@@ -1,36 +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/>.
-
- @author: zoidberg
-"""
-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
@@ -46,23 +61,24 @@ 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))
- if value is None:
+ if not value:
inputs[name] = inputtag.group(3) or ''
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
@@ -70,219 +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
- if hasattr(self, "pyfile"):
- url = self.pyfile.url
+ return res
- 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, "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):
- 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
+ for i in xrange(5 if resumable else 1):
+ header = self.load(url, ref=True, cookies=True, just_header=True, decode=True)
- return getInfo
+ if 'content-disposition' in header or 'content-length' in header:
+ link = url
+ elif 'location' in header and header['location']:
+ location = header['location']
-def timestamp():
- return int(time() * 1000)
+ if not urlparse(location).scheme:
+ p = urlparse(url)
+ base = "%s://%s" % (p.scheme, p.netloc)
+ location = urljoin(base, location)
+ if 'code' in header and header['code'] == 302:
+ link = location
-class PluginParseError(Exception):
- def __init__(self, msg):
- Exception.__init__(self)
- self.value = 'Parse error (%s) - plugin may be out of date' % msg
+ elif resumable:
+ url = location
+ self.logDebug("Redirect #%d to: %s" % (++i, location))
+ continue
- def __str__(self):
- return repr(self.value)
+ 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
+
+
+def secondsToMidnight(gmt=0):
+ now = datetime.utcnow() + timedelta(hours=gmt)
+
+ if now.hour is 0 and now.minute < 10:
+ midnight = now
+ else:
+ midnight = now + timedelta(days=1)
+
+ td = midnight.replace(hour=0, minute=10, second=0, microsecond=0) - now
+
+ if hasattr(td, 'total_seconds'):
+ res = td.total_seconds()
+ else: #@NOTE: work-around for python 2.5 and 2.6 missing timedelta.total_seconds
+ res = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
+
+ return int(res)
class SimpleHoster(Hoster):
- __name__ = "SimpleHoster"
- __version__ = "0.33"
- __pattern__ = None
- __type__ = "hoster"
+ __name__ = "SimpleHoster"
+ __type__ = "hoster"
+ __version__ = "0.82"
+
+ __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")]
+
+
"""
- These patterns should be defined by each hoster:
- FILE_INFO_PATTERN = r'(?P<N>file_name) (?P<S>file_size) (?P<U>units)'
- or FILE_NAME_PATTERN = r'(?P<N>file_name)'
- and FILE_SIZE_PATTERN = r'(?P<S>file_size) (?P<U>units)'
- FILE_OFFLINE_PATTERN = r'File (deleted|not found)'
- TEMP_OFFLINE_PATTERN = r'Server maintainance'
-
- You can also define a PREMIUM_ONLY_PATTERN to detect links that can be downloaded only with a premium account.
+ Info patterns should be defined by each hoster:
+
+ INFO_PATTERN: (optional) Name and Size of the file
+ example: INFO_PATTERN = r'(?P<N>file_name) (?P<S>file_size) (?P<U>size_unit)'
+ or
+ NAME_PATTERN: (optional) Name that will be set for the file
+ example: NAME_PATTERN = r'(?P<N>file_name)'
+ SIZE_PATTERN: (optional) Size that will be checked for the file
+ example: SIZE_PATTERN = r'(?P<S>file_size) (?P<U>size_unit)'
+
+ HASHSUM_PATTERN: (optional) Hash code and type of the file
+ example: HASHSUM_PATTERN = r'(?P<H>hash_code) (?P<T>MD5)'
+
+ OFFLINE_PATTERN: (optional) Check if the page is unreachable
+ example: OFFLINE_PATTERN = r'File (deleted|not found)'
+
+ TEMP_OFFLINE_PATTERN: (optional) Check if the page is temporarily unreachable
+ example: TEMP_OFFLINE_PATTERN = r'Server (maintenance|maintainance)'
+
+
+ Error handling patterns are all optional:
+
+ WAIT_PATTERN: (optional) Detect waiting time
+ example: WAIT_PATTERN = r''
+
+ PREMIUM_ONLY_PATTERN: (optional) Check if the file can be downloaded only with a premium account
+ example: PREMIUM_ONLY_PATTERN = r'Premium account required'
+
+ ERROR_PATTERN: (optional) Detect any error preventing download
+ example: ERROR_PATTERN = r''
+
+
+ Instead overriding handleFree and handlePremium methods you can define the following patterns for direct download:
+
+ LINK_FREE_PATTERN: (optional) group(1) should be the direct link for free download
+ example: LINK_FREE_PATTERN = r'<div class="link"><a href="(.+?)"'
+
+ LINK_PREMIUM_PATTERN: (optional) group(1) should be the direct link for premium download
+ example: LINK_PREMIUM_PATTERN = r'<div class="link"><a href="(.+?)"'
"""
- FILE_SIZE_REPLACEMENTS = []
- FILE_NAME_REPLACEMENTS = [("&#?\w+;", fixup)]
- 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)
+
+ if 'H' in info['pattern']:
+ hashtype = info['pattern']['T'] if 'T' in info['pattern'] else "hash"
+ info[hashtype] = info['pattern']['H']
- 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
+ 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 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 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 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 status == 1:
+ 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)
+
+
+ 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:
+ traffic = self.account.getAccountInfo(self.user, True)['trafficleft']
+
+ 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 e3765602b..572fe95b9 100644
--- a/module/plugins/internal/UnRar.py
+++ b/module/plugins/internal/UnRar.py
@@ -1,132 +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/>.
-
- @author: RaNaN
-"""
-
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"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
- # 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)
CMD = "unrar"
- @staticmethod
- def checkDeps():
+ 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)
+
+
+ @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")
- self.listContent()
- if not self.files:
- raise ArchiveError("Empty Archive")
+ if not self.list():
+ 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)
@@ -134,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
@@ -142,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()
@@ -185,38 +217,37 @@ 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")
# set a password
- if "password" in kwargs and kwargs["password"]:
- args.append("-p%s" % kwargs["password"])
+ if "password" in kwargs and kwargs['password']:
+ args.append("-p%s" % kwargs['password'])
else:
args.append("-p-")
+ if self.keepbroken:
+ args.append("-kb")
+
# NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue
call = [self.CMD, command] + args + list(xargs)
self.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 501962442..5ec56cbdf 100644
--- a/module/plugins/internal/UnZip.py
+++ b/module/plugins/internal/UnZip.py
@@ -1,50 +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.
+import sys
+import zipfile
- 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.Extractor import Extractor, ArchiveError, CRCError, PasswordError
- @author: RaNaN
-"""
-import zipfile
-import sys
+class UnZip(Extractor):
+ __name__ = "UnZip"
+ __version__ = "1.01"
+
+ __description__ = """Zip extractor plugin"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
-from module.plugins.internal.AbstractExtractor import AbtractExtractor
+ EXTENSIONS = ["zip", "zip64"]
-class UnZip(AbtractExtractor):
- __name__ = "UnZip"
- __version__ = "0.1"
- @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 76aff54f0..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/>.
-
- @author: zoidberg
-"""
-
-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
-
- found = re.search(self.VALID_UNTIL_PATTERN, html)
- if found:
- premium = True
- trafficleft = -1
- try:
- self.logDebug(found.group(1))
- validuntil = mktime(strptime(found.group(1), "%d %B %Y"))
- except Exception, e:
- self.logError(e)
- else:
- found = re.search(self.TRAFFIC_LEFT_PATTERN, html)
- if found:
- trafficleft = found.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()