Check-in [e0e28edba2]
Overview
| Comment: | Experiment with a few more target types. Works with a few text editors on STRING. Most just want a uri-list, but can't handle it. |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
e0e28edba26bf906967648092b554b80 |
| User & Date: | mario on 2015-04-19 19:35:57 |
| Other Links: | manifest | tags |
Context
|
2015-04-19
| ||
| 22:17 | Implement in-application row copying per JSON (info=51, mime=json/vnd.streamtuner2.station). Fixed set_text() bug by using set("STRING",..) atom instead. check-in: 38812e4bbf user: mario tags: trunk | |
| 19:35 | Experiment with a few more target types. Works with a few text editors on STRING. Most just want a uri-list, but can't handle it. check-in: e0e28edba2 user: mario tags: trunk | |
| 19:35 | Add plugin defaults. check-in: 6a17061df0 user: mario tags: trunk | |
Changes
Modified action.py from [820487cd33] to [ceb9b4a4e2].
| ︙ | ︙ | |||
387 388 389 390 391 392 393 |
row["url"] = url
new_rows.append(row)
# Or just allow one stream per station in a playlist entry
if not self.multiply:
break
rows = new_rows
| | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
row["url"] = url
new_rows.append(row)
# Or just allow one stream per station in a playlist entry
if not self.multiply:
break
rows = new_rows
debug(dbg.DATA, "conversion to:", dest, " with rows=", rows)
# call conversion schemes
converter = getattr(self, dest) or self.pls
return converter(rows)
# save directly
def file(self, rows, dest, fn):
|
| ︙ | ︙ | |||
458 459 460 461 462 463 464 |
# SMIL
def smil(self, rows):
txt = """<smil>\n<head>\n\t<meta name="title" content="%s"/>\n</head>\n<body>\n\t<seq>\n""" % (rows[0]["title"])
for row in rows:
if row.get("url"):
| | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
# SMIL
def smil(self, rows):
txt = """<smil>\n<head>\n\t<meta name="title" content="%s"/>\n</head>\n<body>\n\t<seq>\n""" % (rows[0]["title"])
for row in rows:
if row.get("url"):
txt += """\t\t<{} src="{}"/>\n""".format(row.get("format", "audio").split("/")[0], row["url"])
txt += """\t</seq>\n</body>\n</smil>\n"""
return txt
# Generate filename for temporary .m3u, if possible with unique id
|
| ︙ | ︙ |
Modified channels/dnd.py from [2bdcd36106] to [3ecc3ca6e1].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # encoding: UTF-8 # api: streamtuner2 # title: Drag and Drop # description: Move streams/stations from and to other applications. # depends: uikit # version: 0.1 # type: interface # category: ui # # Implements Gtk/X11 drag and drop support for station lists. # Should allow to export either just stream URLs, or complete # PLS, XSPF collections. # # Also used by the bookmarks tab to move favourites around. import copy | > > > > > > > > > > | > > > | > > > > > | > > > > > > > > > > | | < > < | > > > > | | | < > | < < < | | > | > > > > > | | | | | < > > | > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# encoding: UTF-8
# api: streamtuner2
# title: Drag and Drop
# description: Move streams/stations from and to other applications.
# depends: uikit
# version: 0.1
# type: interface
# config:
# { name: dnd_format, type: select, value: pls, select: "pls|m3u|xspf|jspf|asx|smil", description: "Default temporary file format for copying a station entry." }
# category: ui
# priority: experimental
#
# Implements Gtk/X11 drag and drop support for station lists.
# Should allow to export either just stream URLs, or complete
# PLS, XSPF collections.
#
# Also used by the bookmarks tab to move favourites around.
# mousepad == ['GTK_TEXT_BUFFER_CONTENTS', 'application/x-gtk-text-buffer-rich-text',
# 'UTF8_STRING', 'COMPOUND_TEXT', 'TEXT', 'STRING',
# 'text/plain;charset=utf-8', 'text/plain']
# libreoffice ==# ['text/plain;charset=utf-8', 'UTF8_STRING', 'application/x-openoffice-embed-source-xml;windows_formatname="Star Embed# Source (XML)"', 'text/richtext', 'text/html',
# 'application/x-openoffice-objectdescriptor-xml;windows_formatname="Star Object Descriptor (XML)";classname="8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6";typename="LibreOffice 4.4 Textdokument";viewaspect="1";width="16999";height="2995";posx="5347";posy="5347"']
import copy
from config import conf, __print__, dbg, json
from uikit import *
import action
# Drag and Drop support
class dnd(object):
module = "dnd"
meta = plugin_meta()
# Keeps selected row on starting DND event
row = None
# Buffer converted types
buf = {}
# Supported type map
drag_types = [
# internal
("json/vnd.streamtuner2.station", 0, 51),
# literal exports
("audio/x-mpegurl", 0, 20),
("application/x-scpls", 0, 21),
("application/xspf+xml", 0, 22),
("application/smil", 0, 23),
("text/html", 0, 23),
("text/richtext", 0, 23),
("application/jspf+json", 0, 25),
# direct srv urls
("text/url", 0, 15), #@TODO: support in action.save_/convert_
("message/external-body", 0, 15),
("url/direct", 0, 15),
# url+comments
("TEXT", 0, 5),
("STRING", 0, 5),
("UTF8_STRING", 0, 5),
("text/plain", 0, 5),
# filename, file:// IRL
("FILE_NAME", 0, 3),
("text/uri-list", 0, 4),
]
cnv_types = {
20: "m3u",
21: "pls",
22: "xspf",
23: "smil",
25: "jspf",
15: "srv",
4: "temp",
5: "srv",
51: "json",
}
# Hook to main, and extend channel tabs
def __init__(self, parent):
self.parent = parent
parent.hooks["init"].append(self.add_dnd)
conf.add_plugin_defaults(self.meta, self.module)
# Attach drag and drop handlers to each channels“ station TreeView
def add_dnd(self, parent):
# visit each module
for cn,module in parent.channels.items():
w = module.gtk_list
# bind SOURCE events
w.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.drag_types, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_COPY|gtk.gdk.ACTION_MOVE)
w.connect('drag-begin', self.begin)
w.connect('drag-data-get', self.data_get)
# bind DESTINATION events
w.enable_model_drag_dest(self.drag_types, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_COPY)
w.connect('drag-drop', self.drop)
w.connect('drag-data-received', self.data_received)
# -- SOURCE, drag'n'drop from ST2 to elsewhere --
# Starting to drag a row
def begin(self, widget, context):
__print__(dbg.UI, "dndāsource: begin-drag, store current row")
self.row = self.treelist_row()
self.buf = {}
uikit.do(context.set_icon_stock, gtk.STOCK_ADD, 16, 16)
return "url" in self.row
# Keep currently selected row when source dragging starts
def treelist_row(self):
cn = self.parent.channel()
row = copy.copy(cn.row())
row.setdefault("format", cn.audioformat)
row.setdefault("listformat", cn.listformat)
row.setdefault("url", row.get("homepage"))
return row
# Target window/app requests data for offered drop
def data_get(self, widget, context, selection, info, time):
__print__(dbg.UI, "dndāsource: data-get, send and convert to requested target type", info, selection.get_target())
# Start new converter if not buffered (because `data_get` gets called mercilessly along the dragging path)
if not info in self.buf:
r = self.row
cnv = action.save_playlist(source=r["listformat"], multiply=False)
# internal JSON row
info = 5
if info >= 51:
buf = 'text', json.dumps(r)
# Pass M3U/PLS/XSPF as literal payload
elif info >= 20:
buf = 'text', cnv.export(urls=[r["url"]], row=r, dest=self.cnv_types[info])
# Direct server URL
elif info >= 10:
urls = action.convert_playlist(r["url"], r["listformat"], "srv", False, r)
#buf = 'uris', urls
buf = 'text', urls[0]
# Text sources are assumed to understand the literal URL or expect a description block
elif info >= 5:
buf = 'text', "{url}\n# Title: {title}\n# Homepage: {homepage}\n\n".format(**r)
# Create temporary PLS file, because "text/uri-list" is widely misunderstood and just implemented for file:// IRLs
else:
tmpfn = "{}/{}.{}".format(conf.tmp, re.sub("[^\w-]+", " ", r["title"]), conf.dnd_format)
cnv.file(rows=[r], dest=conf.dnd_format, fn=tmpfn)
buf = 'uris', ["file://{}".format(tmpfn)] if (info==4) else tmpfn
# Keep in type request buffer
self.buf[info] = buf
# Return prepared data
func, data = self.buf[info]
if func.find("text") >= 0:
selection.set_text(data, len(data))
if func.find("uris") >= 0:
selection.set_uris(data)
return True
# -- DESTINATION, when playlist/url gets dragged in from other app --
# Just a notification for incoming drop
def drop(self, widget, context, x, y, time):
__print__(dbg.UI, "dndādest: drop-probing", context.targets, x, y, time, context.drag_get_selection())
widget.drag_get_data(context, "STRING", time)#context.targets[0], time)
context.drop_reply(True, time)
return True
# Actual data is being passed,
# now has to be converted and patched into stream rows and channel liststore
def data_received(self, widget, context, x, y, selection, info, time):
__print__(dbg.UI, "dndādest: data-receival", info, selection.get_target(), selection.get_uris(), selection.get_text())
context.drop_finish(True, time)
context.finish(True, False, time)
return True
|