2020/06/25 コードの一部修正
#動機
いい本を見つけたとき、その本が図書館にあるかどうか調べたかった。しかし、調べたい図書館のウェブサイトでいちいち検索するのは手間がかかる。そして調べたい図書館が複数ヶ所ある場合はなおさら手間がかかる。そこでそれを手軽にできるように自動化しようと考えた。
#実装方法
iPhoneのカメラで本の裏側のについているバーコードを読み取る。多くの本はバーコードが2個ついているが、上方のバーコード(ISBN13)を読み取る。そして取得したISBNをカーリルのAPIに投げ、指定した図書館にその本があるかどうか検索する。これをすべてiPhoneのアプリであるPythonista上で実装する。
Directory |ー main.py
|ー camera.py
#コード
##main.py
main.py
import requests
import json
import time
import re
import sys
import camera
CALIL_API_KEY = 'Your API Key'
LIBRARYS = ['Univ_Aizu','Fukushima_Aizuwakamatsu']
def main():
#QRコードスキャナーでISBNを取得
ISBN = camera.camera()
#LIBRARYSのList上にある図書館全てで検索する
for lib_key in LIBRARYS:
search_books(ISBN,lib_key)
def search_books(ISBN,lib_key):
print('searching at the library you like...\n')
#いくつかの引数を加えたURL
url = 'http://api.calil.jp/check?appkey{{0}}&isbn={1}&systemid={2}&format=json'.format(CALIL_API_KEY,ISBN,lib_key)
rq = requests.get(url)
#jsonとしてloadするための前処理
prejsn = rq.text.strip('callback(').strip(');')
try:
#strip関数を使いcallback(と);を取り除く,I
jsn = json.loads(prejsn)
#session部のみを抽出する
session = jsn['session']
except json.decoder.JSONDecodeError:
print('Server Error')
#session部がない場合はサーバーエラーとして処理
#その場合はプログラム終了
sys.exit()
try:
#サーバーからのjsonファイルを解析
if jsn['books'][ISBN][lib_key]['status'] == 'Running':
print('loading now...\n')
#Running Stateの場合はサーバーの処理待ち
#ゆえに待機時間5秒をいれる
time.sleep(5)
#Running Stateの場合はサーバーの処理結果を問い合わせるためのURLを取得
reserveurl = jsn['books'][ISBN][lib_key]['reserveurl']
if reserveurl:
#reserveurlがNoneではない場合
bookexist = jsn['books'][ISBN][lib_key]['libkey']
#所在している図書館と貸出状況のみ抽出
lst = list(filter(lambda x:x,re.findall(r'[\w]*',str(bookexist))))
#result=[図書館名,貸出状況]
for num,_ in enumerate(lst):
#図書館名と貸出状況は2つで組である
if num % 2 == 0:
print('{} {}'.format(lst[num],lst[num + 1]))
else:
print('The book does not exist.')
except KeyError:
#要求したKeyがない場合
print(jsn)
print('ERROR')
if __name__ == '__main__':
main()
##camera.py
Pythonista上でQRコードスキャナーを動かすためのコードはここから拝借した。(一部改変)
camera.py
# coding: utf-8
# Barcode scanner demo for Pythonista
# Based on http://www.infragistics.com/community/blogs/torrey-betts/archive/2013/10/10/scanning-barcodes-with-ios-7-objective-c.aspx
from objc_util import *
from ctypes import c_void_p
import ui
import sound
found_codes = set()
main_view = None
AVCaptureSession = ObjCClass('AVCaptureSession')
AVCaptureDevice = ObjCClass('AVCaptureDevice')
AVCaptureDeviceInput = ObjCClass('AVCaptureDeviceInput')
AVCaptureMetadataOutput = ObjCClass('AVCaptureMetadataOutput')
AVCaptureVideoPreviewLayer = ObjCClass('AVCaptureVideoPreviewLayer')
dispatch_get_current_queue = c.dispatch_get_current_queue
dispatch_get_current_queue.restype = c_void_p
def captureOutput_didOutputMetadataObjects_fromConnection_(_self, _cmd, _output, _metadata_objects, _conn):
objects = ObjCInstance(_metadata_objects)
for obj in objects:
s = str(obj.stringValue())
if s not in found_codes:
found_codes.add(s)
sound.play_effect('digital:PowerUp7')
main_view['label'].text = 'Last scan: ' + s
session.stopRunning()
delegate.release()
session.release()
output.release()
if found_codes:
main_view.close()
MetadataDelegate = create_objc_class('MetadataDelegate', methods=[captureOutput_didOutputMetadataObjects_fromConnection_], protocols=['AVCaptureMetadataOutputObjectsDelegate'])
@on_main_thread
def camera():
global main_view
global session
global delegate
global output
global main_view
delegate = MetadataDelegate.new()
main_view = ui.View(frame=(0, 0, 400, 400))
main_view.name = 'Barcode Scanner'
session = AVCaptureSession.alloc().init()
device = AVCaptureDevice.defaultDeviceWithMediaType_('vide')
_input = AVCaptureDeviceInput.deviceInputWithDevice_error_(device, None)
if _input:
session.addInput_(_input)
else:
print('Failed to create input')
return
output = AVCaptureMetadataOutput.alloc().init()
queue = ObjCInstance(dispatch_get_current_queue())
output.setMetadataObjectsDelegate_queue_(delegate, queue)
session.addOutput_(output)
output.setMetadataObjectTypes_(output.availableMetadataObjectTypes())
prev_layer = AVCaptureVideoPreviewLayer.layerWithSession_(session)
prev_layer.frame = ObjCInstance(main_view).bounds()
prev_layer.setVideoGravity_('AVLayerVideoGravityResizeAspectFill')
ObjCInstance(main_view).layer().addSublayer_(prev_layer)
label = ui.Label(frame=(0, 0, 400, 30), flex='W', name='label')
label.background_color = (0, 0, 0, 0.5)
label.text_color = 'white'
label.text = 'Nothing scanned yet'
label.alignment = ui.ALIGN_CENTER
main_view.add_subview(label)
session.startRunning()
main_view.present('sheet')
#the 64 line code waiting code
main_view.wait_modal()
return(''.join(found_codes))
if __name__ == '__main__':
camera()