2020-02-09 18:51:58 +09:00
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
|
|
|
|
|
|
# python
|
|
|
|
|
|
import os
|
2020-02-11 20:43:20 +09:00
|
|
|
|
import traceback
|
2020-02-09 18:51:58 +09:00
|
|
|
|
import tempfile
|
|
|
|
|
|
from threading import Thread
|
|
|
|
|
|
import json
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from enum import Enum
|
|
|
|
|
|
|
2020-03-10 17:56:36 +09:00
|
|
|
|
# sjva 공용, 패키지
|
|
|
|
|
|
import framework.common.celery as celery_shutil
|
2020-02-09 18:51:58 +09:00
|
|
|
|
from .plugin import logger
|
|
|
|
|
|
|
2020-03-10 17:56:36 +09:00
|
|
|
|
|
2020-02-09 18:51:58 +09:00
|
|
|
|
class Status(Enum):
|
2020-07-23 23:00:02 +09:00
|
|
|
|
READY = 0
|
|
|
|
|
|
START = 1
|
|
|
|
|
|
DOWNLOADING = 2
|
|
|
|
|
|
ERROR = 3
|
|
|
|
|
|
FINISHED = 4
|
|
|
|
|
|
STOP = 5
|
|
|
|
|
|
COMPLETED = 6
|
|
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
|
str_list = [
|
|
|
|
|
|
'준비',
|
|
|
|
|
|
'분석중',
|
|
|
|
|
|
'다운로드중',
|
|
|
|
|
|
'실패',
|
|
|
|
|
|
'변환중',
|
|
|
|
|
|
'중지',
|
|
|
|
|
|
'완료'
|
|
|
|
|
|
]
|
|
|
|
|
|
return str_list[self.value]
|
2020-02-09 18:51:58 +09:00
|
|
|
|
|
2020-03-15 15:29:32 +09:00
|
|
|
|
|
2020-07-25 03:06:03 +09:00
|
|
|
|
class MyYoutubeDL(object):
|
2020-08-08 15:33:14 +09:00
|
|
|
|
DEFAULT_FILENAME = '%(title)s-%(id)s.%(ext)s'
|
|
|
|
|
|
|
2020-07-25 03:06:03 +09:00
|
|
|
|
__index = 0
|
2020-07-23 23:00:02 +09:00
|
|
|
|
_last_msg = ''
|
|
|
|
|
|
|
2021-01-11 22:31:35 +09:00
|
|
|
|
def __init__(self, plugin, url, filename, temp_path, save_path=None, opts=None, dateafter=None, datebefore=None):
|
2020-11-15 14:06:33 +09:00
|
|
|
|
# from youtube_dl.utils import DateRange
|
|
|
|
|
|
from .plugin import YOUTUBE_DL_PACKAGE
|
|
|
|
|
|
DateRange = __import__('%s.utils' % YOUTUBE_DL_PACKAGE, fromlist=['DateRange']).DateRange
|
2020-11-08 22:58:35 +09:00
|
|
|
|
|
2020-07-23 23:00:02 +09:00
|
|
|
|
if save_path is None:
|
|
|
|
|
|
save_path = temp_path
|
|
|
|
|
|
if opts is None:
|
|
|
|
|
|
opts = {}
|
|
|
|
|
|
self.plugin = plugin
|
|
|
|
|
|
self.url = url
|
|
|
|
|
|
self.filename = filename
|
|
|
|
|
|
if not os.path.isdir(temp_path):
|
|
|
|
|
|
os.makedirs(temp_path)
|
|
|
|
|
|
self.temp_path = tempfile.mkdtemp(prefix='youtube-dl_', dir=temp_path)
|
|
|
|
|
|
if not os.path.isdir(save_path):
|
|
|
|
|
|
os.makedirs(save_path)
|
|
|
|
|
|
self.save_path = save_path
|
|
|
|
|
|
self.opts = opts
|
2020-11-08 22:58:35 +09:00
|
|
|
|
if dateafter or datebefore:
|
|
|
|
|
|
self.opts['daterange'] = DateRange(start=dateafter, end=datebefore)
|
2020-07-25 03:06:03 +09:00
|
|
|
|
self.index = MyYoutubeDL.__index
|
|
|
|
|
|
MyYoutubeDL.__index += 1
|
|
|
|
|
|
self.__status = Status.READY
|
|
|
|
|
|
self.__thread = None
|
2020-07-23 23:00:02 +09:00
|
|
|
|
self.key = None
|
2021-02-11 18:08:47 +09:00
|
|
|
|
self.start_time = None # 시작 시간
|
|
|
|
|
|
self.end_time = None # 종료 시간
|
2020-08-01 16:38:13 +09:00
|
|
|
|
# info_dict에서 얻는 정보
|
|
|
|
|
|
self.info_dict = {
|
2021-02-11 18:08:47 +09:00
|
|
|
|
'extractor': None, # 타입
|
|
|
|
|
|
'title': None, # 제목
|
|
|
|
|
|
'uploader': None, # 업로더
|
|
|
|
|
|
'uploader_url': None # 업로더 주소
|
2020-07-23 23:00:02 +09:00
|
|
|
|
}
|
|
|
|
|
|
# info_dict에서 얻는 정보(entries)
|
|
|
|
|
|
# self.info_dict['playlist_index'] = None
|
2021-02-11 18:08:47 +09:00
|
|
|
|
# self.info_dict['duration'] = None # 길이
|
|
|
|
|
|
# self.info_dict['format'] = None # 포맷
|
|
|
|
|
|
# self.info_dict['thumbnail'] = None # 썸네일
|
2020-08-01 16:38:13 +09:00
|
|
|
|
# progress_hooks에서 얻는 정보
|
|
|
|
|
|
self.progress_hooks = {
|
2021-02-11 18:08:47 +09:00
|
|
|
|
'downloaded_bytes': None, # 다운로드한 크기
|
|
|
|
|
|
'total_bytes': None, # 전체 크기
|
|
|
|
|
|
'eta': None, # 예상 시간(s)
|
|
|
|
|
|
'speed': None # 다운로드 속도(bytes/s)
|
2020-07-23 23:00:02 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
|
|
if self.status != Status.READY:
|
|
|
|
|
|
return False
|
2020-07-25 03:06:03 +09:00
|
|
|
|
self.__thread = Thread(target=self.run)
|
|
|
|
|
|
self.__thread.start()
|
2020-07-23 23:00:02 +09:00
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def run(self):
|
2020-11-15 14:06:33 +09:00
|
|
|
|
# import youtube_dl
|
|
|
|
|
|
from .plugin import YOUTUBE_DL_PACKAGE
|
|
|
|
|
|
youtube_dl = __import__('%s' % YOUTUBE_DL_PACKAGE)
|
2020-07-23 23:00:02 +09:00
|
|
|
|
import glob2
|
2020-11-08 22:58:35 +09:00
|
|
|
|
|
2020-07-23 23:00:02 +09:00
|
|
|
|
try:
|
|
|
|
|
|
self.start_time = datetime.now()
|
|
|
|
|
|
self.status = Status.START
|
2020-08-01 16:38:13 +09:00
|
|
|
|
# 동영상 정보 가져오기
|
2020-12-07 23:59:36 +09:00
|
|
|
|
info_dict = MyYoutubeDL.get_info_dict(self.url, self.opts.get('proxy'), self.opts.get('cookiefile'))
|
2020-08-01 16:38:13 +09:00
|
|
|
|
if info_dict is None:
|
2020-07-23 23:00:02 +09:00
|
|
|
|
self.status = Status.ERROR
|
|
|
|
|
|
return
|
|
|
|
|
|
self.info_dict['extractor'] = info_dict['extractor']
|
2020-12-13 00:45:52 +09:00
|
|
|
|
self.info_dict['title'] = info_dict.get('title', info_dict['id'])
|
2020-10-10 14:06:44 +09:00
|
|
|
|
self.info_dict['uploader'] = info_dict.get('uploader', '')
|
|
|
|
|
|
self.info_dict['uploader_url'] = info_dict.get('uploader_url', '')
|
2020-07-23 23:00:02 +09:00
|
|
|
|
ydl_opts = {
|
|
|
|
|
|
'logger': MyLogger(),
|
|
|
|
|
|
'progress_hooks': [self.my_hook],
|
|
|
|
|
|
# 'match_filter': self.match_filter_func,
|
|
|
|
|
|
'outtmpl': os.path.join(self.temp_path, self.filename),
|
|
|
|
|
|
'ignoreerrors': True,
|
|
|
|
|
|
'cachedir': False
|
|
|
|
|
|
}
|
|
|
|
|
|
ydl_opts.update(self.opts)
|
|
|
|
|
|
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
|
|
|
|
|
|
ydl.download([self.url])
|
2020-10-05 18:17:47 +09:00
|
|
|
|
if self.status in (Status.START, Status.FINISHED): # 다운로드 성공
|
2020-07-23 23:00:02 +09:00
|
|
|
|
for i in glob2.glob(self.temp_path + '/**/*'):
|
|
|
|
|
|
path = i.replace(self.temp_path, self.save_path, 1)
|
|
|
|
|
|
if os.path.isdir(i):
|
|
|
|
|
|
if not os.path.isdir(path):
|
|
|
|
|
|
os.mkdir(path)
|
|
|
|
|
|
continue
|
2020-08-01 16:38:13 +09:00
|
|
|
|
celery_shutil.move(i, path)
|
2020-07-23 23:00:02 +09:00
|
|
|
|
self.status = Status.COMPLETED
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
self.status = Status.ERROR
|
|
|
|
|
|
logger.error('Exception:%s', e)
|
|
|
|
|
|
logger.error(traceback.format_exc())
|
|
|
|
|
|
finally:
|
2020-08-01 16:38:13 +09:00
|
|
|
|
# 임시폴더 삭제
|
|
|
|
|
|
celery_shutil.rmtree(self.temp_path)
|
2020-07-23 23:00:02 +09:00
|
|
|
|
if self.status != Status.STOP:
|
|
|
|
|
|
self.end_time = datetime.now()
|
|
|
|
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
|
|
if self.status in (Status.ERROR, Status.STOP, Status.COMPLETED):
|
|
|
|
|
|
return False
|
|
|
|
|
|
self.status = Status.STOP
|
|
|
|
|
|
self.end_time = datetime.now()
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
|
def get_version():
|
2020-11-15 14:06:33 +09:00
|
|
|
|
# from youtube_dl.version import __version__
|
|
|
|
|
|
from .plugin import YOUTUBE_DL_PACKAGE
|
|
|
|
|
|
__version__ = __import__('%s.version' % YOUTUBE_DL_PACKAGE, fromlist=['__version__']).__version__
|
2020-11-08 22:58:35 +09:00
|
|
|
|
|
|
|
|
|
|
return __version__
|
2020-07-23 23:00:02 +09:00
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2020-12-07 15:07:05 +09:00
|
|
|
|
def get_info_dict(url, proxy=None, cookiefile=None):
|
2020-11-15 14:06:33 +09:00
|
|
|
|
# import youtube_dl
|
|
|
|
|
|
from .plugin import YOUTUBE_DL_PACKAGE
|
|
|
|
|
|
youtube_dl = __import__('%s' % YOUTUBE_DL_PACKAGE)
|
2020-07-23 23:00:02 +09:00
|
|
|
|
try:
|
|
|
|
|
|
ydl_opts = {
|
|
|
|
|
|
'simulate': True,
|
|
|
|
|
|
'dump_single_json': True,
|
|
|
|
|
|
'extract_flat': 'in_playlist',
|
|
|
|
|
|
'logger': MyLogger()
|
|
|
|
|
|
}
|
|
|
|
|
|
if proxy:
|
|
|
|
|
|
ydl_opts['proxy'] = proxy
|
2020-12-07 15:07:05 +09:00
|
|
|
|
if cookiefile:
|
|
|
|
|
|
ydl_opts['cookiefile'] = cookiefile
|
2020-07-23 23:00:02 +09:00
|
|
|
|
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
|
|
|
|
|
|
ydl.download([url])
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error('Exception:%s', e)
|
|
|
|
|
|
logger.error(traceback.format_exc())
|
|
|
|
|
|
return None
|
2020-07-25 03:06:03 +09:00
|
|
|
|
return json.loads(MyYoutubeDL._last_msg)
|
2020-07-23 23:00:02 +09:00
|
|
|
|
|
|
|
|
|
|
def my_hook(self, d):
|
|
|
|
|
|
if self.status != Status.STOP:
|
|
|
|
|
|
self.status = {
|
|
|
|
|
|
'downloading': Status.DOWNLOADING,
|
|
|
|
|
|
'error': Status.ERROR,
|
2020-10-09 19:16:22 +09:00
|
|
|
|
'finished': Status.FINISHED # 다운로드 완료. 변환 시작
|
2020-07-23 23:00:02 +09:00
|
|
|
|
}[d['status']]
|
|
|
|
|
|
if d['status'] != 'error':
|
|
|
|
|
|
self.filename = os.path.basename(d.get('filename'))
|
|
|
|
|
|
self.progress_hooks['downloaded_bytes'] = d.get('downloaded_bytes')
|
|
|
|
|
|
self.progress_hooks['total_bytes'] = d.get('total_bytes')
|
|
|
|
|
|
self.progress_hooks['eta'] = d.get('eta')
|
|
|
|
|
|
self.progress_hooks['speed'] = d.get('speed')
|
|
|
|
|
|
|
|
|
|
|
|
def match_filter_func(self, info_dict):
|
|
|
|
|
|
self.info_dict['playlist_index'] = info_dict['playlist_index']
|
|
|
|
|
|
self.info_dict['duration'] = info_dict['duration']
|
|
|
|
|
|
self.info_dict['format'] = info_dict['format']
|
|
|
|
|
|
self.info_dict['thumbnail'] = info_dict['thumbnail']
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
def status(self):
|
2020-07-25 03:06:03 +09:00
|
|
|
|
return self.__status
|
2020-07-23 23:00:02 +09:00
|
|
|
|
|
|
|
|
|
|
@status.setter
|
|
|
|
|
|
def status(self, value):
|
|
|
|
|
|
from .plugin import socketio_emit
|
2020-11-08 22:58:35 +09:00
|
|
|
|
|
2020-07-25 03:06:03 +09:00
|
|
|
|
self.__status = value
|
2020-07-23 23:00:02 +09:00
|
|
|
|
socketio_emit('status', self)
|
2020-03-19 00:32:24 +09:00
|
|
|
|
|
2020-03-15 15:29:32 +09:00
|
|
|
|
|
2020-02-09 18:51:58 +09:00
|
|
|
|
class MyLogger(object):
|
2020-07-23 23:00:02 +09:00
|
|
|
|
def debug(self, msg):
|
2020-07-25 03:06:03 +09:00
|
|
|
|
MyYoutubeDL._last_msg = msg
|
2020-07-23 23:00:02 +09:00
|
|
|
|
if msg.find('') != -1 or msg.find('{') != -1:
|
2020-08-01 16:38:13 +09:00
|
|
|
|
# 과도한 로그 방지
|
|
|
|
|
|
return
|
2020-07-23 23:00:02 +09:00
|
|
|
|
logger.debug(msg)
|
2020-02-09 18:51:58 +09:00
|
|
|
|
|
2020-07-23 23:00:02 +09:00
|
|
|
|
def warning(self, msg):
|
|
|
|
|
|
logger.warning(msg)
|
2020-02-09 18:51:58 +09:00
|
|
|
|
|
2020-07-23 23:00:02 +09:00
|
|
|
|
def error(self, msg):
|
|
|
|
|
|
logger.error(msg)
|