add quality selection

This commit is contained in:
Alex 2019-12-13 22:43:58 +02:00
parent 34ec89485f
commit 13e690dd63
7 changed files with 38 additions and 16 deletions

View file

@ -62,9 +62,10 @@ dqueue = DownloadQueue(config, Notifier())
async def add(request): async def add(request):
post = await request.json() post = await request.json()
url = post.get('url') url = post.get('url')
if not url: quality = post.get('quality')
if not url or not quality:
raise web.HTTPBadRequest() raise web.HTTPBadRequest()
status = await dqueue.add(url) status = await dqueue.add(url, quality)
return web.Response(text=serializer.encode(status)) return web.Response(text=serializer.encode(status))
@routes.post(config.URL_PREFIX + 'delete') @routes.post(config.URL_PREFIX + 'delete')

View file

@ -32,8 +32,15 @@ class DownloadInfo:
class Download: class Download:
manager = None manager = None
def __init__(self, download_dir, info): def __init__(self, download_dir, quality, info):
self.download_dir = download_dir self.download_dir = download_dir
if quality == 'best':
self.format = None
elif quality in ('1080p', '720p', '480p'):
res = quality[:-1]
self.format = f'bestvideo[height<={res}]+bestaudio/best[height<={res}]'
else:
raise Exception(f'unknown quality {quality}')
self.info = info self.info = info
self.canceled = False self.canceled = False
self.tmpfilename = None self.tmpfilename = None
@ -49,6 +56,7 @@ class Download:
'no_color': True, 'no_color': True,
#'skip_download': True, #'skip_download': True,
'outtmpl': os.path.join(self.download_dir, '%(title)s.%(ext)s'), 'outtmpl': os.path.join(self.download_dir, '%(title)s.%(ext)s'),
'format': self.format,
'cachedir': False, 'cachedir': False,
'socket_timeout': 30, 'socket_timeout': 30,
'progress_hooks': [lambda d: self.status_queue.put(d)], 'progress_hooks': [lambda d: self.status_queue.put(d)],
@ -121,29 +129,29 @@ class DownloadQueue:
'extract_flat': True, 'extract_flat': True,
}).extract_info(url, download=False) }).extract_info(url, download=False)
async def __add_entry(self, entry, already): async def __add_entry(self, entry, quality, already):
etype = entry.get('_type') or 'video' etype = entry.get('_type') or 'video'
if etype == 'playlist': if etype == 'playlist':
entries = entry['entries'] entries = entry['entries']
log.info(f'playlist detected with {len(entries)} entries') log.info(f'playlist detected with {len(entries)} entries')
results = [] results = []
for etr in entries: for etr in entries:
results.append(await self.__add_entry(etr, already)) results.append(await self.__add_entry(etr, quality, already))
if any(res['status'] == 'error' for res in results): if any(res['status'] == 'error' for res in results):
return {'status': 'error', 'msg': ', '.join(res['msg'] for res in results if res['status'] == 'error' and 'msg' in res)} return {'status': 'error', 'msg': ', '.join(res['msg'] for res in results if res['status'] == 'error' and 'msg' in res)}
return {'status': 'ok'} return {'status': 'ok'}
elif etype == 'video' or etype == 'url' and 'id' in entry: elif etype == 'video' or etype == 'url' and 'id' in entry:
if entry['id'] not in self.queue: if entry['id'] not in self.queue:
dl = DownloadInfo(entry['id'], entry['title'], entry.get('webpage_url') or entry['url']) dl = DownloadInfo(entry['id'], entry['title'], entry.get('webpage_url') or entry['url'])
self.queue[entry['id']] = Download(self.config.DOWNLOAD_DIR, dl) self.queue[entry['id']] = Download(self.config.DOWNLOAD_DIR, quality, dl)
self.event.set() self.event.set()
await self.notifier.added(dl) await self.notifier.added(dl)
return {'status': 'ok'} return {'status': 'ok'}
elif etype == 'url': elif etype == 'url':
return await self.add(entry['url'], already) return await self.add(entry['url'], quality, already)
return {'status': 'error', 'msg': f'Unsupported resource "{etype}"'} return {'status': 'error', 'msg': f'Unsupported resource "{etype}"'}
async def add(self, url, already=None): async def add(self, url, quality, already=None):
log.info(f'adding {url}') log.info(f'adding {url}')
already = set() if already is None else already already = set() if already is None else already
if url in already: if url in already:
@ -155,7 +163,7 @@ class DownloadQueue:
entry = await asyncio.get_running_loop().run_in_executor(None, self.__extract_info, url) entry = await asyncio.get_running_loop().run_in_executor(None, self.__extract_info, url)
except youtube_dl.utils.YoutubeDLError as exc: except youtube_dl.utils.YoutubeDLError as exc:
return {'status': 'error', 'msg': str(exc)} return {'status': 'error', 'msg': str(exc)}
return await self.__add_entry(entry, already) return await self.__add_entry(entry, quality, already)
async def cancel(self, ids): async def cancel(self, ids):
for id in ids: for id in ids:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 979 KiB

After

Width:  |  Height:  |  Size: 885 KiB

Before After
Before After

View file

@ -19,11 +19,14 @@
<div class="input-group add-url-box"> <div class="input-group add-url-box">
<input type="text" class="form-control" placeholder="Video or playlist URL" name="addUrl" [(ngModel)]="addUrl" [disabled]="addInProgress || downloads.loading"> <input type="text" class="form-control" placeholder="Video or playlist URL" name="addUrl" [(ngModel)]="addUrl" [disabled]="addInProgress || downloads.loading">
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-primary" type="submit" (click)="addDownload()" [disabled]="addInProgress || downloads.loading"> <select class="custom-select" name="quality" [(ngModel)]="quality" [disabled]="addInProgress || downloads.loading">
<span class="spinner-border spinner-border-sm" role="status" id="add-spinner" *ngIf="addInProgress"></span> <option *ngFor="let q of qualities" [ngValue]="q.id">{{ q.text }}</option>
{{ addInProgress ? "Adding..." : "Add" }} </select>
</button>
</div> </div>
<button class="btn btn-primary add-url" type="submit" (click)="addDownload()" [disabled]="addInProgress || downloads.loading">
<span class="spinner-border spinner-border-sm" role="status" id="add-spinner" *ngIf="addInProgress"></span>
{{ addInProgress ? "Adding..." : "Add" }}
</button>
</div> </div>
</form> </form>

View file

@ -2,6 +2,9 @@
max-width: 720px max-width: 720px
margin: 4rem auto margin: 4rem auto
button.add-url
min-width: 7rem
$metube-section-color-bg: rgba(0,0,0,.07) $metube-section-color-bg: rgba(0,0,0,.07)
.metube-section-header .metube-section-header

View file

@ -11,6 +11,13 @@ import { MasterCheckboxComponent } from './master-checkbox.component';
}) })
export class AppComponent implements AfterViewInit { export class AppComponent implements AfterViewInit {
addUrl: string; addUrl: string;
qualities: Array<Object> = [
{id: "best", text: "Best"},
{id: "1080p", text: "1080p"},
{id: "720p", text: "720p"},
{id: "480p", text: "480p"}
];
quality: string = "best";
addInProgress = false; addInProgress = false;
@ViewChild('queueMasterCheckbox', {static: false}) queueMasterCheckbox: MasterCheckboxComponent; @ViewChild('queueMasterCheckbox', {static: false}) queueMasterCheckbox: MasterCheckboxComponent;
@ -61,7 +68,7 @@ export class AppComponent implements AfterViewInit {
addDownload() { addDownload() {
this.addInProgress = true; this.addInProgress = true;
this.downloads.add(this.addUrl).subscribe((status: Status) => { this.downloads.add(this.addUrl, this.quality).subscribe((status: Status) => {
if (status.status === 'error') { if (status.status === 'error') {
alert(`Error adding URL: ${status.msg}`); alert(`Error adding URL: ${status.msg}`);
} else { } else {

View file

@ -79,8 +79,8 @@ export class DownloadsService {
return of({status: 'error', msg: msg}) return of({status: 'error', msg: msg})
} }
public add(url: string) { public add(url: string, quality: string) {
return this.http.post<Status>('add', {url: url}).pipe( return this.http.post<Status>('add', {url: url, quality: quality}).pipe(
catchError(this.handleHTTPError) catchError(this.handleHTTPError)
); );
} }