Tried to improve scheduling algorithm and added WebUI support as requested in #2

This commit is contained in:
JohnDoee
2015-07-19 19:18:59 +02:00
parent a9dae5bc90
commit 52661abf52
3 changed files with 146 additions and 25 deletions

View File

@@ -42,6 +42,7 @@ import json
import logging
import math
import os
import time
import urllib
from collections import defaultdict
@@ -324,11 +325,16 @@ class TorrentHandler(object):
current_buffer_offset = 20
break
currently_downloading = set()
for peer in self.torrent.handle.get_peer_info():
if peer.downloading_piece_index != -1:
currently_downloading.add(peer.downloading_piece_index)
status_increase_count = 0
current_buffer = 0
found_buffer_end = False
for chunk, chunk_status in enumerate(self.torrent.status.pieces[offset:tf.last_chunk+1], offset):
if not chunk_status:
if not chunk_status and chunk not in currently_downloading:
if not found_buffer_end:
logger.debug('Found buffer end at %s, have a buffer of %s' % (chunk, current_buffer))
found_buffer_end = True
@@ -339,7 +345,7 @@ class TorrentHandler(object):
self.torrent_handle.piece_priority(chunk, 1)
status_increase_count += 1
elif not found_buffer_end:
elif not found_buffer_end and chunk not in currently_downloading:
current_buffer += 1
if status_increase_count >= max(MIN_QUEUE_CHUNKS, current_buffer-current_buffer_offset):
@@ -350,6 +356,7 @@ class TorrentHandler(object):
return bool(handled_heads)
def update_chunk_priorities(self): # TODO: check if torrent still exists
start_time = time.time()
file_progress = self.torrent.get_status(['file_progress'])['file_progress']
incomplete_files = False
@@ -380,21 +387,22 @@ class TorrentHandler(object):
del self.core.torrent_handlers[self.torrent_id]
return
reactor.callLater(2, self.update_chunk_priorities)
logger.debug('Took %s seconds to handle a loop' % (time.time() - start_time))
reactor.callLater(1, self.update_chunk_priorities)
def blackhole_all_pieces(self, first_chunk, last_chunk):
for chunk in range(first_chunk, last_chunk+1):
self.torrent_handle.piece_priority(chunk, 0)
@defer.inlineCallbacks
def get_file(self, filepath):
def get_file(self, filepath_or_index):
status = self.torrent.get_status(['piece_length', 'files', 'file_priorities', 'file_progress', 'state', 'save_path'])
pieces = self.torrent.status.pieces
piece_length = status['piece_length']
files = status['files']
for f, priority, progress in zip(files, status['file_priorities'], status['file_progress']):
if f['path'] == filepath:
for i, f, priority, progress in zip(range(len(files)), files, status['file_priorities'], status['file_progress']):
if i == filepath_or_index or f['path'] == filepath_or_index:
f['first_piece'] = f['offset'] / piece_length
f['last_piece'] = (f['offset'] + f['size']) / piece_length
f['pieces'] = pieces[f['first_piece']:f['last_piece']+1]
@@ -534,14 +542,14 @@ class Core(CorePluginBase):
@export
@defer.inlineCallbacks
def stream_torrent(self, tid, filepath):
def stream_torrent(self, tid, filepath_or_index):
try:
torrent_handler = yield self.get_torrent_handler(tid)
except UnknownTorrentException: # torrent isn't added yet
defer.returnValue({'status': 'error', 'message': 'torrent_not_found'})
try:
tf = yield torrent_handler.get_file(filepath)
tf = yield torrent_handler.get_file(filepath_or_index)
except UnknownFileException:
defer.returnValue({'status': 'error', 'message': 'file_not_found'})

View File

@@ -31,20 +31,139 @@ Copyright:
statement from all source files in the program, then also delete it here.
*/
PreferencePage = Ext.extend(Ext.Panel, {
title: 'Streaming',
border: false,
layout: 'form',
initComponent: function() {
PreferencePage.superclass.initComponent.call(this);
var om = this.optionsManager = new Deluge.OptionsManager();
this.on('show', this.onPageShow, this);
var fieldset = this.add({
xtype: 'fieldset',
border: false,
title: 'Streaming',
style: 'margin-bottom: 0px; padding-bottom: 0px; padding-top: 5px',
autoHeight: true,
labelWidth: 110,
defaultType: 'textfield',
defaults: {
width: 180,
}
});
om.bind('port', fieldset.add({
name: 'port',
fieldLabel: _('Port'),
decimalPrecision: 0,
minValue: -1,
maxValue: 99999
}));
om.bind('ip', fieldset.add({
name: 'ip',
fieldLabel: 'IP'
}));
om.bind('reset_complete', fieldset.add({
xtype: 'checkbox',
name: 'reset_complete',
fieldLabel: 'Reset "do not download" when streamed file is complete',
}));
om.bind('allow_remote', fieldset.add({
xtype: 'checkbox',
name: 'allow_remote',
fieldLabel: 'Allow remote control checkbox',
}));
om.bind('remote_username', fieldset.add({
name: 'remote_username',
fieldLabel: 'Remote username'
}));
om.bind('remote_password', fieldset.add({
name: 'remote_password',
inputType: 'password',
fieldLabel: 'Remote password'
}));
},
onApply: function() {
var changed = this.optionsManager.getDirty();
if (!Ext.isObjectEmpty(changed)) {
deluge.client.streaming.set_config(changed, {
success: this.onSetConfig,
scope: this
});
for (var key in deluge.config) {
deluge.config[key] = this.optionsManager.get(key);
}
}
},
onSetConfig: function() {
this.optionsManager.commit();
},
onGotConfig: function(config) {
this.optionsManager.set(config);
},
onPageShow: function() {
deluge.client.streaming.get_config({
success: this.onGotConfig,
scope: this
})
}
});
StreamingPlugin = Ext.extend(Deluge.Plugin, {
constructor: function(config) {
config = Ext.apply({
name: "Streaming"
}, config);
StreamingPlugin.superclass.constructor.call(this, config);
},
'name': 'Streaming',
onDisable: function() {
deluge.menus.filePriorities.remove('streamthis');
deluge.preferences.selectPage(_('Plugins'));
deluge.preferences.removePage(this.prefsPage);
this.prefsPage.destroy();
},
onEnable: function() {
onEnable: function() {
this.prefsPage = new PreferencePage();
deluge.preferences.addPage(this.prefsPage);
console.log('Streaming plugin loaded');
deluge.menus.filePriorities.addMenuItem({
id: 'streamthis',
text: 'Stream this file',
iconCls: 'icon-down',
handler: function (item, event) {
deluge.menus.filePriorities.hide();
var files = deluge.details.items.items[2];
var nodes = files.getSelectionModel().getSelectedNodes();
if (nodes) {
var fileIndex = nodes[0].attributes.fileIndex;
var tid = files.torrentId;
if (fileIndex >= 0) {
deluge.client.streaming.stream_torrent(tid, fileIndex, {
success: function (result) {
if (result.status == 'success') {
Ext.Msg.alert('Stream ready', 'URL for stream: <a target="_blank" href="' + result.url + '">' + result.url + '</a>');
} else {
Ext.Msg.alert('Stream failed', 'Error message: ' + result.message);
}
}
})
}
}
return false;
}
});
}
});
new StreamingPlugin();
Deluge.registerPlugin('Streaming', StreamingPlugin);

View File

@@ -46,10 +46,4 @@ from common import get_resource
class WebUI(WebPluginBase):
scripts = [get_resource("streaming.js")]
def enable(self):
pass
def disable(self):
pass
scripts = [get_resource("streaming.js")]