├── tests ├── __init__.py ├── runtests.py ├── test_util.py ├── test_common.py └── util.py ├── lulu ├── util │ ├── __init__.py │ ├── parser.py │ ├── strings.py │ ├── term.py │ ├── git.py │ ├── fs.py │ └── log.py ├── cli_wrapper │ ├── __init__.py │ ├── player │ │ ├── wmp.py │ │ ├── mplayer.py │ │ ├── dragonplayer.py │ │ ├── gnome_mplayer.py │ │ ├── vlc.py │ │ └── __init__.py │ └── transcoder │ │ ├── ffmpeg.py │ │ ├── libav.py │ │ ├── __init__.py │ │ └── mencoder.py ├── version.py ├── processor │ ├── __init__.py │ ├── join_ts.py │ └── rtmpdump.py ├── __init__.py ├── extractors │ ├── khan.py │ ├── joy.py │ ├── dilidili.py │ ├── tudou.py │ ├── cbs.py │ ├── alive.py │ ├── archive.py │ ├── ku6.py │ ├── giphy.py │ ├── freesound.py │ ├── magisto.py │ ├── ehow.py │ ├── huomaotv.py │ ├── quanmin.py │ ├── douyin.py │ ├── bandcamp.py │ ├── iqilu.py │ ├── metacafe.py │ ├── ted.py │ ├── bcy.py │ ├── heavymusic.py │ ├── pixivision.py │ ├── kuaishou.py │ ├── musicplayon.py │ ├── facebook.py │ ├── icourses.py │ ├── theplatform.py │ ├── iwara.py │ ├── naver.py │ ├── veoh.py │ ├── vidto.py │ ├── kuwo.py │ ├── vine.py │ ├── dailymotion.py │ ├── w56.py │ ├── douban.py │ ├── suntv.py │ ├── baomihua.py │ ├── yizhibo.py │ ├── qq_egame.py │ ├── qingting.py │ ├── soundcloud.py │ ├── panda.py │ ├── mtv81.py │ ├── videomega.py │ ├── kugou.py │ ├── ifeng.py │ ├── fantasy.py │ ├── vk.py │ ├── nicovideo.py │ ├── nanagogo.py │ ├── pinterest.py │ ├── infoq.py │ ├── __init__.py │ ├── yinyuetai.py │ ├── pixnet.py │ ├── yixia.py │ ├── fc2video.py │ ├── huaban.py │ ├── lizhi.py │ ├── toutiao.py │ ├── showroom.py │ ├── instagram.py │ ├── zhanqi.py │ ├── bigthink.py │ ├── tucao.py │ ├── weibo.py │ ├── qie_video.py │ ├── cntv.py │ ├── douyutv.py │ ├── sohu.py │ ├── imgur.py │ ├── ckplayer.py │ ├── ixigua.py │ ├── longzhu.py │ ├── bokecc.py │ ├── qie.py │ ├── wanmen.py │ ├── twitter.py │ ├── ximalaya.py │ ├── coub.py │ └── google.py ├── json_output.py └── __main__.py ├── MANIFEST.in ├── lulu.plugin.zsh ├── Pipfile ├── codecov.yml ├── bin └── lulu ├── fabfile.py ├── .travis.yml ├── appveyor.yml ├── .coveragerc ├── contrib └── completion │ ├── lulu-completion.bash │ ├── lulu.fish │ └── _lulu ├── LICENSE ├── README.rst ├── .gitignore └── setup.py /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/util/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/player/wmp.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/player/mplayer.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/transcoder/ffmpeg.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/transcoder/libav.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst LICENSE 2 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/player/dragonplayer.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/player/gnome_mplayer.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/transcoder/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/transcoder/mencoder.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/player/vlc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | -------------------------------------------------------------------------------- /lulu/cli_wrapper/player/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from .mplayer import * 4 | -------------------------------------------------------------------------------- /lulu/version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __version__ = '0.5.3' 4 | script_name = 'lulu' 5 | -------------------------------------------------------------------------------- /lulu.plugin.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | alias lulu="noglob python3 $(dirname $0)/bin/lulu" 3 | alias lulu-vlc="noglob python3 $(dirname $0)/bin/lulu --player vlc" 4 | -------------------------------------------------------------------------------- /lulu/processor/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from .join_flv import concat_flv 4 | from .join_mp4 import concat_mp4 5 | from .ffmpeg import * 6 | from .rtmpdump import * 7 | -------------------------------------------------------------------------------- /lulu/util/parser.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | from bs4 import BeautifulSoup 4 | 5 | 6 | def get_parser(page): 7 | parser = BeautifulSoup(page, 'html.parser') 8 | return parser 9 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | 3 | url = "https://pypi.python.org/simple" 4 | verify_ssl = true 5 | 6 | 7 | [dev-packages] 8 | 9 | twine = "*" 10 | ipdb = "*" 11 | 12 | 13 | [packages] 14 | 15 | coverage = "==4.4.2" 16 | cryptography = "==2.1.4" 17 | beautifulsoup4 = "==4.6.0" 18 | requests = "==2.18.4" 19 | -------------------------------------------------------------------------------- /lulu/util/strings.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | from html import unescape 4 | 5 | from lulu.util.fs import legitimize 6 | 7 | 8 | def get_filename(htmlstring): 9 | return legitimize(unescape(htmlstring)) 10 | 11 | 12 | def parameterize(string): 13 | return "'{}'".format(string.replace("'", r"'\''")) 14 | -------------------------------------------------------------------------------- /tests/runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | import unittest 5 | 6 | 7 | TEST_MODULES = [ 8 | 'tests.test_util', 9 | 'tests.test_common', 10 | 'tests.test_extractors', 11 | ] 12 | 13 | 14 | def all(): 15 | return unittest.defaultTestLoader.loadTestsFromNames(TEST_MODULES) 16 | 17 | 18 | if __name__ == '__main__': 19 | unittest.main(defaultTest='all') 20 | -------------------------------------------------------------------------------- /lulu/util/term.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | def get_terminal_size(): 5 | """Get (width, height) of the current terminal.""" 6 | try: 7 | # fcntl module only available on Unix 8 | import fcntl 9 | import termios 10 | import struct 11 | return struct.unpack('hh', fcntl.ioctl(1, termios.TIOCGWINSZ, '1234')) 12 | except Exception: 13 | return (40, 80) 14 | -------------------------------------------------------------------------------- /lulu/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # This file is Python 2 compliant. 3 | 4 | import sys 5 | 6 | if sys.version_info[0] == 3: 7 | #from .extractor import Extractor, VideoExtractor 8 | #from .util import log 9 | 10 | from .__main__ import * 11 | 12 | #from .common import * 13 | #from .version import * 14 | #from .cli_wrapper import * 15 | #from .extractor import * 16 | else: 17 | # Don't import anything. 18 | pass 19 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | token: c430fe31-42ab-4fa4-81c3-f4109f1912a1 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "70...100" 8 | 9 | status: 10 | project: 11 | default: on 12 | patch: 13 | default: on 14 | changes: 15 | default: off 16 | 17 | comment: 18 | layout: "header, reach, diff, flags, files, footer" 19 | behavior: default 20 | require_changes: no 21 | require_base: no 22 | require_head: yes 23 | -------------------------------------------------------------------------------- /bin/lulu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | 6 | _srcdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 7 | _filepath = os.path.dirname(sys.argv[0]) 8 | sys.path.insert(1, os.path.join(_filepath, _srcdir)) 9 | 10 | 11 | if sys.version_info[0] == 3: 12 | import lulu 13 | if __name__ == '__main__': 14 | lulu.main() 15 | else: # Python 2 16 | from lulu.util import log 17 | log.e('[fatal] Python 3 is required!') 18 | -------------------------------------------------------------------------------- /lulu/util/git.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | 6 | def get_head(repo_path): 7 | """Get (branch, commit) from HEAD of a git repo.""" 8 | try: 9 | ref = open( 10 | os.path.join(repo_path, '.git', 'HEAD'), 'r' 11 | ).read().strip()[5:].split('/') 12 | branch = ref[-1] 13 | commit = open( 14 | os.path.join(repo_path, '.git', *ref), 'r' 15 | ).read().strip()[:7] 16 | return branch, commit 17 | except Exception: 18 | return None 19 | -------------------------------------------------------------------------------- /fabfile.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | from fabric.api import ( 4 | local, 5 | ) 6 | 7 | 8 | def test(proxy=False): 9 | cmd = 'PYTHONPATH=./ {} coverage run tests/runtests.py'.format( 10 | 'proxychains4 -q' if proxy else '' 11 | ) 12 | local(cmd) 13 | 14 | 15 | def test_download(func): 16 | ''' 17 | fab test_download:acfun 18 | ''' 19 | cmd = ( 20 | 'PYTHONPATH=./ python tests/test_extractors.py ' 21 | 'TestExtractors.test_{}'.format(func) 22 | ) 23 | local(cmd) 24 | 25 | 26 | def upload(): 27 | local( 28 | 'python3 setup.py upload' 29 | ) 30 | -------------------------------------------------------------------------------- /tests/test_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import unittest 4 | 5 | from lulu.util import fs 6 | from lulu.util import parser 7 | 8 | 9 | class TestUtil(unittest.TestCase): 10 | def test_legitimize(self): 11 | self.assertEqual(fs.legitimize('1*2', os='Linux'), '1*2') 12 | self.assertEqual(fs.legitimize('1*2', os='Darwin'), '1*2') 13 | self.assertEqual(fs.legitimize('1*2', os='Windows'), '1-2') 14 | 15 | def test_parser(self): 16 | p = parser.get_parser('