diff --git a/resources/images/news/columbusdispatch.png b/resources/images/news/columbusdispatch.png new file mode 100644 index 0000000000..7f5671a3e3 Binary files /dev/null and b/resources/images/news/columbusdispatch.png differ diff --git a/resources/recipes/columbusdispatch.recipe b/resources/recipes/columbusdispatch.recipe new file mode 100644 index 0000000000..e021f55048 --- /dev/null +++ b/resources/recipes/columbusdispatch.recipe @@ -0,0 +1,80 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class ColumbusDispatchRecipe(BasicNewsRecipe): + __license__ = 'GPL v3' + __author__ = 'kwetal' + language = 'en' + version = 1 + + title = u'The Columbus Dispatch' + publisher = u'The Columbus Dispatch' + category = u'News, Newspaper' + description = u'Daily newspaper from central Ohio' + + use_embedded_content = False + remove_empty_feeds = True + oldest_article = 1.2 + max_articles_per_feed = 100 + + no_stylesheets = True + remove_javascript = True + encoding = 'utf-8' + # Seems to work best, but YMMV + simultaneous_downloads = 2 + + # Feeds from http://www.dispatch.com/live/content/rss/index.html + feeds = [] + feeds.append((u'News: Local and state news', u'http://www.dispatch.com/live/static/crt/2_rss_localnews.xml')) + feeds.append((u'News: National news', u'http://www.dispatch.com/live/static/crt/2_rss_nationalnews.xml')) + feeds.append((u'News: Editorials', u'http://www.dispatch.com/live/static/crt/2_rss_editorials.xml')) + feeds.append((u'News: Columnists', u'http://www.dispatch.com/live/static/crt/2_rss_columnists.xml')) + feeds.append((u'News: Health news', u'http://www.dispatch.com/live/static/crt/2_rss_health.xml')) + feeds.append((u'News: Science news', u'http://www.dispatch.com/live/static/crt/2_rss_science.xml')) + feeds.append((u'Sports: OSU football', u'http://www.dispatch.com/live/static/crt/2_rss_osufootball.xml')) + feeds.append((u'Sports: OSU men\'s basketball', u'http://www.dispatch.com/live/static/crt/2_rss_osumensbball.xml')) + feeds.append((u'Sports: OSU women\'s basketball', u'http://www.dispatch.com/live/static/crt/2_rss_osuwomensbball.xml')) + feeds.append((u'Sports: OSU sports', u'http://www.dispatch.com/live/static/crt/2_rss_osusports.xml')) + feeds.append((u'Sports: Blue Jackets', u'http://www.dispatch.com/live/static/crt/2_rss_bluejackets.xml')) + feeds.append((u'Sports: Crew', u'http://www.dispatch.com/live/static/crt/2_rss_crew.xml')) + feeds.append((u'Sports: Clippers', u'http://www.dispatch.com/live/static/crt/2_rss_clippers.xml')) + feeds.append((u'Sports: Indians', u'http://www.dispatch.com/live/static/crt/2_rss_indians.xml')) + feeds.append((u'Sports: Reds', u'http://www.dispatch.com/live/static/crt/2_rss_reds.xml')) + feeds.append((u'Sports: Golf', u'http://www.dispatch.com/live/static/crt/2_rss_golf.xml')) + feeds.append((u'Sports: Outdoors', u'http://www.dispatch.com/live/static/crt/2_rss_outdoors.xml')) + feeds.append((u'Sports: Cavs/NBA', u'http://www.dispatch.com/live/static/crt/2_rss_cavaliers.xml')) + feeds.append((u'Sports: High Schools', u'http://www.dispatch.com/live/static/crt/2_rss_highschools.xml')) + feeds.append((u'Sports: Browns', u'http://www.dispatch.com/live/static/crt/2_rss_browns.xml')) + feeds.append((u'Sports: Bengals', u'http://www.dispatch.com/live/static/crt/2_rss_bengals.xml')) + feeds.append((u'Sports: Auto Racing', u'http://www.dispatch.com/live/static/crt/2_rss_autoracing.xml')) + feeds.append((u'Business News', u'http://www.dispatch.com/live/static/crt/2_rss_business.xml')) + feeds.append((u'Features: Weekender', u'http://www.dispatch.com/live/static/crt/2_rss_weekender.xml')) + feeds.append((u'Features: Life and Arts', u'http://www.dispatch.com/live/static/crt/2_rss_lifearts.xml')) + feeds.append((u'Features: Food', u'http://www.dispatch.com/live/static/crt/2_rss_food.xml')) + feeds.append((u'Features: NOW! for kids', u'http://www.dispatch.com/live/static/crt/2_rss_now.xml')) + feeds.append((u'Features: Travel', u'http://www.dispatch.com/live/static/crt/2_rss_travel.xml')) + feeds.append((u'Features: Home and Garden', u'http://www.dispatch.com/live/static/crt/2_rss_homegarden.xml')) + feeds.append((u'Features: Faith and Values', u'http://www.dispatch.com/live/static/crt/2_rss_faithvalues.xml')) + #feeds.append((u'', u'')) + + keep_only_tags = [] + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'colhed'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'hed'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'subhed'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'date'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'byline'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'srcline'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'body'})) + + remove_tags = [] + remove_tags.append(dict(name = 'div', attrs = {'id': 'middle-story-ad-container'})) + + extra_css = ''' + body {font-family:verdana,arial,helvetica,geneva,sans-serif ;} + a {text-decoration: none; color: blue;} + div.colhed {font-weight: bold;} + div.hed {font-size: xx-large; font-weight: bold; margin-bottom: 0.2em;} + div.subhed {font-size: large;} + div.date {font-size: x-small; font-style: italic; color: #666666; margin-top: 0.4em; margin-bottom: 0.4em;} + div.byline, div.srcline {font-size: small; color: #696969;} + ''' + diff --git a/src/calibre/devices/usbobserver/Makefile b/src/calibre/devices/usbobserver/Makefile index ee98e75bd6..dc14d4ac8d 100644 --- a/src/calibre/devices/usbobserver/Makefile +++ b/src/calibre/devices/usbobserver/Makefile @@ -2,11 +2,7 @@ usbobserver.so : usbobserver.o gcc -arch i386 -arch ppc -bundle usbobserver.o -o usbobserver.so -framework Python -framework IOKit -framework CoreFoundation usbobserver.o : usbobserver.c - gcc -arch i386 -arch ppc -dynamic -I/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -c usbobserver.c -o usbobserver.o - - -install : usbobserver.so - cp usbobserver.so /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/ + gcc -arch i386 -arch ppc -dynamic -I/Library/Frameworks/Python.framework/Versions/Current/Headers -c usbobserver.c -o usbobserver.o clean : rm -f *.o *.so diff --git a/src/calibre/devices/usbobserver/usbobserver.c b/src/calibre/devices/usbobserver/usbobserver.c index a6238f1005..ad30ad6e53 100644 --- a/src/calibre/devices/usbobserver/usbobserver.c +++ b/src/calibre/devices/usbobserver/usbobserver.c @@ -26,28 +26,34 @@ #include #include +#include #include +CFStringRef USB_PROPS[3] = { CFSTR("USB Vendor Name"), CFSTR("USB Product Name"), CFSTR("USB Serial Number") }; + +static PyObject* +get_iokit_string_property(io_service_t dev, int prop) { + CFTypeRef PropRef; + char buf[500]; + + PropRef = IORegistryEntryCreateCFProperty(dev, USB_PROPS[prop], kCFAllocatorDefault, 0); + if (PropRef) { + if(!CFStringGetCString(PropRef, buf, 500, kCFStringEncodingUTF8)) buf[0] = '\0'; + } else buf[0] = '\0'; + + return PyUnicode_DecodeUTF8(buf, strlen(buf), "replace"); +} + static PyObject * usbobserver_get_usb_devices(PyObject *self, PyObject *args) { - mach_port_t masterPort; CFMutableDictionaryRef matchingDict; kern_return_t kr; - /* Create a master port for communication with IOKit */ - kr = IOMasterPort(MACH_PORT_NULL, &masterPort); - - if (kr || !masterPort) { - PyErr_SetString(PyExc_RuntimeError, "Couldn't create master IOKit port"); - return NULL; - } - //Set up matching dictionary for class IOUSBDevice and its subclasses matchingDict = IOServiceMatching(kIOUSBDeviceClassName); if (!matchingDict) { PyErr_SetString(PyExc_RuntimeError, "Couldn't create a USB matching dictionary"); - mach_port_deallocate(mach_task_self(), masterPort); return NULL; } @@ -58,12 +64,12 @@ usbobserver_get_usb_devices(PyObject *self, PyObject *args) { SInt32 score; IOUSBDeviceInterface182 **dev = NULL; UInt16 vendor, product, bcd; + PyObject *manufacturer, *productn, *serial; PyObject *devices, *device; devices = PyList_New(0); if (devices == NULL) { PyErr_NoMemory(); - mach_port_deallocate(mach_task_self(), masterPort); return NULL; } @@ -85,7 +91,15 @@ usbobserver_get_usb_devices(PyObject *self, PyObject *args) { kr = (*dev)->GetDeviceVendor(dev, &vendor); kr = (*dev)->GetDeviceProduct(dev, &product); kr = (*dev)->GetDeviceReleaseNumber(dev, &bcd); - device = Py_BuildValue("(iii)", vendor, product, bcd); + + manufacturer = get_iokit_string_property(usbDevice, 0); + if (manufacturer == NULL) manufacturer = Py_None; + productn = get_iokit_string_property(usbDevice, 1); + if (productn == NULL) productn = Py_None; + serial = get_iokit_string_property(usbDevice, 2); + if (serial == NULL) serial = Py_None; + + device = Py_BuildValue("(iiiOOO)", vendor, product, bcd, manufacturer, productn, serial); if (device == NULL) { IOObjectRelease(usbDevice); (*plugInInterface)->Release(plugInInterface); @@ -109,11 +123,7 @@ usbobserver_get_usb_devices(PyObject *self, PyObject *args) { Py_DECREF(device); } - - //Finished with master port - mach_port_deallocate(mach_task_self(), masterPort); - - return Py_BuildValue("N", devices); + return devices; } static PyMethodDef usbobserver_methods[] = {