Advertisement
47kza32b

dmm2ssw.py

Jan 23rd, 2018
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 26.25 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. '''DMMのURIからページを取得し素人系総合wiki用ウィキテキストを作成する
  4.  
  5. 書式:
  6. dmm2ssw.py DMM作品ページのURI [オプション...]
  7.  
  8.  
  9. 説明:
  10.    オプションで与えられない情報は可能な限りDMMのページから取得してウィキテキスト
  11.    を作成し標準出力へ出力する。
  12.  
  13.    タイトルに「(ハート)」と「◆」があった場合は「♥」に置き換える。
  14.    その他wiki構文上問題のある文字列があれば置き換える。
  15.    置き換えた場合、元のDMM上のタイトルはコメントとして残す(検索用)。
  16.    ただし -d オプションが与えられるとこれらの変更は行わない。
  17.  
  18.    女優名に過去の芸名が付記されている場合(「現在の芸名 (旧芸名...)」)は旧芸名を
  19.    除去する。
  20.    ただし -o オプションが与えられると除去しない。
  21.  
  22.    女優ページ用の他、シリーズ一覧ページ用に表(table)形式のウィキテキストも作成
  23.    できる。
  24.  
  25.    DVD通販、DVDレンタル、動画-ビデオ/-素人、および月額動画のページには対応して
  26.    いるはず。
  27.  
  28.  
  29. オプション:
  30. -a, --actress 出演者 [出演者 ...]
  31.    クレジットされてない出演者を追加する場合用。
  32.    出演者(のwikiページ名)を指定する。
  33.    DMMページ上にすでに出演者情報が存在する場合はその末尾に追加される。
  34.    -n 指定も含め2名に満たない場合は出力されない。
  35.  
  36. -n, --number 出演者数
  37.    未知の出演者がいる場合用。
  38.    出演者の総数を指定する。
  39.    指定されると出演者の最後に「… ほか計n名」を追加する。
  40.    既知の出演者数以下の場合は無視される。
  41.  
  42. -s, --series シリーズ一覧ページ名
  43.    DMM上でのシリーズとwikiでのシリーズの扱いが異なる場合用。
  44.    wiki上で作品が記載されているシリーズ(メーカー、レーベル)一覧ページの名前を
  45.    指定する。
  46.    指定されるとDMMページ上のものを置き換える。
  47.  
  48. -t, --table
  49.    シリーズページ用の表(table)形式のウィキテキストのみ出力する。
  50.    -tt と同時に指定できない。
  51.  
  52. -tt, --with-table
  53.    シリーズページ用の表(table)形式のウィキテキストも出力する。
  54.    -t と同時に指定できない。
  55.  
  56. --pid 品番
  57.    -t/-tt オプションが与えられた時用。
  58.    作品の品番を直接指定する。
  59.  
  60.    ※指定しない場合
  61.    DMM上の品番情報(cid=)から自動生成を試みる。
  62.    正規表現にマッチした場合置き換えられ、すべて大文字化される。
  63.    マッチしても正しい品番にならない場合があるので注意。
  64.    マッチしなかったら変更せずそのまま出力する。
  65.  
  66.    自動生成パターン(python正規表現)と置換文字列:
  67.  
  68.    '^(?:h_|)\d*([a-z]+)(\d+r?).*', '\1-\2'
  69.  
  70.    (cid=)1hunt569     ⇒ HUNT-569
  71.    (cid=)41hrdv01212r ⇒ HRDV-01212R
  72.    (cid=)h_093crc035  ⇒ CRC-035
  73.  
  74.    ※正しく生成できない例
  75.    (cid=)h_093r18243  ⇒ ×R-18243 (○R18-243)
  76.    (cid=)125ud537ra   ⇒ ×UD-537R (○UD537R)
  77.  
  78. --subtitle 副題
  79.    -t/-tt オプションが与えられた時用。
  80.    作品名の副題(SUBTITLEカラムに出力される)に指定された副題を出力する。
  81.  
  82. --note 備考
  83.    通常形式ではウィキテキストの最後、表形式では右端の「NOTE」カラムに指定された
  84.    文字列を出力する。
  85.  
  86. --extra 文字列 [文字列 ...]
  87.    通常形式では備考の上に、表形式では「NOTE」の左に任意のカラムを追加し、そこに
  88.    文字列を出力する。
  89.  
  90. --follow-redirect
  91.    指定・取得した出演者名のページがリダイレクトページだった場合にリダイレクト先
  92.    のリンクを付加する。
  93.    出演者が複数いた場合のwikiへの問い合わせ間隔は3秒。
  94.  
  95. -m, --disable-modify-title
  96.    タイトルの自動修正を無効にする(「説明」参照)。
  97.  
  98. -o, --disable-strip-oldname
  99.    出演者の旧名の自動除去を無効にする(「説明」参照)。
  100.  
  101. -c, --clear-cache
  102.    httplib2使用時に作成されるHTTPキャッシュを終了時に削除する(「注意」参照)。
  103.    httplib2を使用していない場合は無視される。
  104.  
  105. -v, --verbose
  106.    デバッグ用情報を出力する。
  107.  
  108. -V, --version
  109.    バージョン情報を表示して終了する。
  110.  
  111. -h, --help
  112.    ヘルプメッセージを表示して終了する。
  113.  
  114.  
  115. 動作条件:
  116.    [必須] python3
  117.    - python2では動作しない。
  118.    [推奨] httplib2 (python3用)
  119.    - なければ標準ライブラリを使用するが、その場合ページ取得時サーバにかかる負荷
  120.    が比較して大きくなる。頻繁に使うならhttplib2の使用を強く推奨。
  121.    そして標準ライブラリではあまりテストしていない。
  122.  
  123.  
  124. 注意:
  125.    ページによってはデータの取得に失敗するかもしれない(HTMLの整形が異なっていたり
  126.    ブラウザは許容できてもHTMLParserはできない構文ミスがあったりすることがある)。
  127.  
  128.    このスクリプトを連続実行させて短時間に大量の情報を取得した場合、その間隔が
  129.    短いと(D)DoS攻撃とみなされて通報されるかもしれないので注意。
  130.  
  131.    httplib2を使用している場合、OSのテンポラリディレクトリ (C:\TEMP や /tmp
  132.    など) にディレクトリ 'dmm2ssw_cache' を作成し、そこにHTTPレスポンスや
  133.    コンテンツをキャッシュする。
  134.    キャッシュを自分でクリアしたい場合はディレクトリごと直接消すか -c オプション
  135.    を指定する。
  136.  
  137. 更新履歴:
  138.    20120901 https://pastebin.com/Vds3M5Rn
  139.    20120901.1 https://pastebin.com/X5urzKrA
  140.    20180123.0 文字コード判定変換追加
  141.  
  142. '''
  143. __version__ = 20180123.0
  144.  
  145. import os
  146. import sys
  147. import re
  148. import argparse
  149. import time
  150. import urllib.parse
  151. from tempfile    import gettempdir
  152. from shutil      import rmtree
  153. from html.parser import HTMLParser
  154.  
  155. HTTPLIB2 = True
  156. try:
  157.     # httplib2があれば使う
  158.     import httplib2
  159. except ImportError:
  160.     # なければurllib.requestを使う (非推奨)
  161.     import urllib.request, urllib.error
  162.     HTTPLIB2 = False
  163.  
  164. OWNNAME  = os.path.splitext(os.path.basename(__file__))[0]
  165. CACHEDIR = gettempdir() + '/dmm2ssw_cache'
  166. VERBOSE  = 0
  167. MSGLEVEL = {'E': 'ERROR',
  168.             'W': 'WARNING',
  169.             'I': 'INFO'}
  170.  
  171. p_cid    = re.compile(r'/cid=(.+)/')
  172. p_acts   = re.compile(r'/article=actress/')
  173. p_dir    = re.compile(r'/article=director/')
  174. p_series = re.compile(r'/article=series/')
  175. p_maker  = re.compile(r'/article=maker/')
  176. p_label  = re.compile(r'/article=label/')
  177. p_rdate  = re.compile(r'\d{4}/\d{2}/\d{2}')
  178.  
  179. sp_tsuffix = (re.compile(r' - \S*( - DMM.R18|)$'), '')
  180. sp_oldname = (re.compile(r'[((].*$'), '')
  181. sp_heart   = (re.compile(r'(ハート)|◆'), r'♥')
  182. sp_bracket = (re.compile(r'\[(.*)\]'), r'[\1]')
  183. sp_pid     = (re.compile(r'^(?:h_|)\d*([a-z]+)(\d+r?).*', re.I), r'\1-\2')
  184. sp_wikis   = (re.compile(r'href=(/.*/)>'), r'href="\1">')
  185.  
  186. SUMMARY    = {}
  187. AUTOMODIFY = True
  188. AUTOSTRIP  = True
  189.  
  190.  
  191. def verbose(msg):
  192.     '''デバッグ用情報の出力'''
  193.     if VERBOSE:
  194.         print('({0}): >>> {1}'.format(OWNNAME, msg), file=sys.stderr)
  195.         sys.stderr.flush()
  196.  
  197.  
  198. def stderror(level, msg):
  199.     '''標準エラー出力へメッセージ出力'''
  200.     print('({0}): {1} ** {2}'.format(OWNNAME, MSGLEVEL[level], msg),
  201.           file=sys.stderr)
  202.     sys.stderr.flush()
  203.     if level == 'E':
  204.         # エラーなら終了
  205.         raise SystemExit('({0}): ** プログラムを終了します。'.format(OWNNAME))
  206.  
  207.  
  208. def uri_openerror(name, info):
  209.     '''URIオープン時のエラーメッセージ'''
  210.     stderror('E', 'URIを開く時にエラーが発生しました ({0})。詳細: {1}'.format(name, info))
  211.  
  212.  
  213. def sub(p_list, string, n=False):
  214.     '''re.sub()、re.subn()ラッパー'''
  215.     return p_list[0].subn(p_list[1], string) if n \
  216.         else p_list[0].sub(p_list[1], string)
  217.  
  218.  
  219. def get_args():
  220.     '''コマンドライン引数の解釈'''
  221.     global VERBOSE
  222.  
  223.     parser = argparse.ArgumentParser(
  224.         description='DMMのURIから素人系総合wiki用ウィキテキストを作成する')
  225.     parser.add_argument('uri',
  226.                         help='DMMの作品ページのURI',
  227.                         metavar='URI',)
  228.     parser.add_argument('-a', '--actress',
  229.                         help='出演者 (DMMページ内のものに追加する)',
  230.                         nargs='+',
  231.                         default=())
  232.     parser.add_argument('-n', '--number',
  233.                         help='未知の出演者がいる場合の総出演者数 (… ほか計NUMBER名)',
  234.                         type=int,
  235.                         default=0)
  236.     parser.add_argument('-s', '--series',
  237.                         help='シリーズ名 (DMMページ内のものを置き換える)')
  238.  
  239.     table = parser.add_mutually_exclusive_group()
  240.     table.add_argument('-t', '--table',
  241.                        help='シリーズページ用の表形式ウィキテキストのみ作成する',
  242.                        action='store_const',
  243.                        dest='table',
  244.                        const=2,
  245.                        default=0)
  246.     table.add_argument('-tt', '--with-table',
  247.                        help='シリーズページ用の表形式ウィキテキストも作成する',
  248.                        action='store_const',
  249.                        dest='table',
  250.                        const=1,
  251.                        default=0)
  252.  
  253.     parser.add_argument('--pid',
  254.                         help='作品の品番 (-t/-tt 指定時用)',
  255.                         default='')
  256.     parser.add_argument('--subtitle',
  257.                         help='タイトルの副題 (-t/-tt 指定時用)',
  258.                         default='')
  259.     parser.add_argument('--note',
  260.                         help='備考として出力する文字列',
  261.                         default='')
  262.     parser.add_argument('--extra',
  263.                         help='備考以外に任意のカラムと文字列を追加する',
  264.                         metavar='STRING',
  265.                         nargs='*',
  266.                         default=())
  267.     parser.add_argument('--follow-redirect',
  268.                         help='出演者名ページのリダイレクト先を取得する',
  269.                         action='store_true')
  270.  
  271.     parser.add_argument('-m', '--disable-modify-title',
  272.                         help='タイトルの自動調整を無効にする',
  273.                         action='store_false')
  274.     parser.add_argument('-o', '--disable-strip-oldname',
  275.                         help='出演者の旧芸名の自動除去を無効にする',
  276.                         action='store_false')
  277.     parser.add_argument('-c', '--clear-cache',
  278.                         help='プログラム終了時にHTTPキャッシュをクリアする',
  279.                         action='store_true')
  280.     parser.add_argument('-v', '--verbose',
  281.                         help='デバッグ用情報を出力する',
  282.                         action='append_const',
  283.                         const=1,
  284.                         default=[])
  285.     parser.add_argument('-V', '--version',
  286.                         help='バージョン情報を表示して終了する',
  287.                         action='version',
  288.                         version='%(prog)s {}'.format(__version__))
  289.     args = parser.parse_args()
  290.  
  291.     VERBOSE = VERBOSE or args.verbose.count(1)
  292.     if VERBOSE:
  293.         verbose('Verbose mode on')
  294.         verbose('args: {}'.format(args))
  295.  
  296.     return args
  297.  
  298. def open_uri(uri):
  299.     '''URIを開いて読み込む'''
  300.     if HTTPLIB2:
  301.         verbose('Use httplib2')
  302.         if VERBOSE > 1: httplib2.debuglevel = 1
  303.         h = httplib2.Http(CACHEDIR)
  304.         verbose('cachedir: ' + CACHEDIR)
  305.         try:
  306.             resp, rawhtml = h.request(uri)
  307.         except (httplib2.RelativeURIError,
  308.                 httplib2.ServerNotFoundError) as e:
  309.             uri_openerror(e.__class__.__name__, ", ".join(e.args))
  310.     else:
  311.         verbose('Use urllib')
  312.         if VERBOSE > 1:
  313.             from http.client import HTTPConnection
  314.             HTTPConnection.debuglevel = 1
  315.         try:
  316.             rawhtml = urllib.request.urlopen(uri).read()
  317.             #return urllib.request.build_opener().open(SUMMARY['uri'])
  318.         except urllib.error.HTTPError as e:
  319.             uri_openerror(e.__class__.__name__, '{0} {1}'.format(e.code, e.msg))
  320.         except urllib.error.URLError as e:
  321.             uri_openerror(e.__class__.__name__, e.reason)
  322.         except ValueError as e:
  323.             uri_openerror(e.__class__.__name__, ", ".join(e.args))
  324.    
  325.     # 文字コード判定変換(古いページはEUC-JP、最近のものはUTF-8)
  326.     temphtml = rawhtml.decode()
  327.     if temphtml.find('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />') != -1:
  328.         return temphtml
  329.     return rawhtml.decode('euc-jp', 'ignore')
  330.  
  331.  
  332. def retrieve_title(title):
  333.     '''タイトルの採取と調整'''
  334.     verbose('title_tag: "{}"'.format(title))
  335.  
  336.     # タイトルの後に付く文字列の除去
  337.     on_dmm = modified = sub(sp_tsuffix, title)
  338.     if AUTOMODIFY:
  339.         # ♥の代替文字列の置き換え
  340.         modified = sub(sp_heart, modified)
  341.         # wiki構文と衝突する文字列の置き換え
  342.         modified = sub(sp_bracket, modified)
  343.  
  344.     if on_dmm != modified:
  345.         SUMMARY['title']     = modified
  346.         SUMMARY['title_dmm'] = on_dmm
  347.     else:
  348.         SUMMARY['title'] = on_dmm
  349.  
  350.     verbose('title:     "{}"'.format(SUMMARY['title']))
  351.     verbose('title_dmm: "{}"'.format(SUMMARY['title_dmm']))
  352.  
  353.  
  354. class DMMParser(HTMLParser):
  355.     '''HTMLの解析'''
  356.     def __init__(self):
  357.         HTMLParser.__init__(self)
  358.         self.content = ''
  359.         self.block   = ''
  360.         self.img_lg  = ''
  361.         self.img_p   = ''
  362.         self.alist   = []
  363.         self.dlist   = []
  364.         self.blabel  = {'出演者:':  ('actress',  p_acts),
  365.                         '監督:':    ('director', p_dir),
  366.                         'シリーズ:': ('series',   p_series),
  367.                         'メーカー:': ('maker',    p_maker),
  368.                         'レーベル:': ('label',    p_label)}
  369.  
  370.     def handle_starttag(self, tag, attrs):
  371.         global SUMMARY
  372.  
  373.         attr_dict = dict(attrs)
  374.  
  375.         if tag == 'title':
  376.             # タイトルの検出
  377.             self.content = 'title'
  378.             verbose('title tag found')
  379.         elif tag == 'meta' and attr_dict.get('property') == 'og:image':
  380.             # 画像(小)のURIの採取
  381.             SUMMARY['image_sm'] = attr_dict['content']
  382.             verbose('image sm: ' + attr_dict['content'])
  383.         elif tag == 'div' and attr_dict.get('id') == 'sample-video':
  384.             # 画像のあるブロックの開始
  385.             self.block = 'image'
  386.         elif self.block == 'image' and tag == 'img' and 'src' in attr_dict:
  387.             # フォールバック用画像
  388.             self.img_p = attr_dict['src']
  389.             verbose('image c p : ' + self.img_p)
  390.         elif self.block == 'image' \
  391.                 and tag == 'a' and attr_dict.get('name') == 'package-image':
  392.             # 画像(大)のURIの採取
  393.             self.img_lg = attr_dict['href']
  394.             verbose('image c lg: ' + self.img_lg)
  395.         elif self.block in self.blabel and tag == 'a' and 'href' in attr_dict:
  396.             # 出演者、監督、シリーズ、またはメーカーのリンクの検出
  397.             href = attr_dict['href']
  398.             if self.blabel[self.block][1].search(href):
  399.                 self.content = self.blabel[self.block][0]
  400.                 verbose('{} link found'.format(self.content))
  401.  
  402.     def handle_endtag(self, tag):
  403.  
  404.         if self.block == 'image' and tag == 'div':
  405.             # 画像(大)の決定
  406.             SUMMARY['image_lg'] = self.img_lg or self.img_p
  407.             verbose('image lg: ' + SUMMARY['image_lg'])
  408.             self.block = self.img_lg = self.img_p = ''
  409.         elif self.block in ('出演者:', '監督:') and tag == 'tr':
  410.             # 出演者または監督ブロックの終了
  411.             verbose('block {} end'.format(self.block))
  412.             verbose('{}: {}'.format(self.blabel[self.block][0],
  413.                                     SUMMARY[self.blabel[self.block][0]]))
  414.             self.block = ''
  415.  
  416.     def handle_data(self, data):
  417.         global SUMMARY
  418.  
  419.         data = data.strip()
  420.  
  421.         if self.content == 'title':
  422.             # タイトルの採取および調整
  423.             retrieve_title(data)
  424.  
  425.         elif data in ('発売日:', '貸出開始日:', '配信開始日:'):
  426.             # 発売日情報ブロックの開始をマーク
  427.             self.block = 'release'
  428.             verbose('relase date marked')
  429.         elif self.block == 'release' and p_rdate.match(data):
  430.             # 発売日の採取
  431.             rdate = data.replace('/', '.')
  432.             SUMMARY['release'] = rdate
  433.             verbose('release: ' + rdate)
  434.             self.block = ''
  435.         elif data in self.blabel:
  436.             # 出演者、監督、シリーズ、メーカー、およびレーベルブロックの開始をマーク
  437.             self.block = data
  438.             verbose('block {} marked'.format(data))
  439.  
  440.         # 出演者、監督、シリーズ、メーカー、およびレーベルの実際の文字列の取得
  441.         elif self.content == 'actress':
  442.             verbose('actress_orig: ' + data)
  443.             if AUTOSTRIP:
  444.                 data = sub(sp_oldname, data)
  445.             SUMMARY[self.content].append(data)
  446.         elif self.content == 'director':
  447.             verbose('director_orig: ' + data)
  448.             SUMMARY[self.content].append(data)
  449.         elif self.content in ('series', 'maker', 'label'):
  450.             SUMMARY[self.content] = data
  451.             verbose(self.content + ': ' + data)
  452.             self.block = ''
  453.  
  454.         self.content = ''
  455.  
  456.  
  457. class SswRedirectDest(HTMLParser):
  458.     '''wikiリダイレクトの検出'''
  459.     def __init__(self):
  460.         HTMLParser.__init__(self)
  461.         self.flg_div   = False
  462.         self.flg_redir = False
  463.         self.flg_dest  = False
  464.         self.dest      = ''
  465.  
  466.     def handle_starttag(self, tag, attrs):
  467.         if not self.flg_div \
  468.                 and tag == 'div' and attrs == [('class', 'user-area')]:
  469.             self.flg_div = True
  470.             verbose('ssw.div found')
  471.         elif self.flg_div and self.flg_redir and tag == 'a':
  472.             self.flg_dest = True
  473.             verbose('ssw.dest found')
  474.  
  475.     def handle_data(self, data):
  476.  
  477.         data = data.strip()
  478.  
  479.         if self.flg_div and data == 'リダイレクト:':
  480.             self.flg_redir = True
  481.             verbose('ssw.redir found')
  482.         elif self.flg_dest:
  483.             self.dest = data
  484.             verbose('dest: {}'.format(data))
  485.  
  486.     def handle_endtag(self, tag):
  487.         if self.flg_dest and tag == 'a':
  488.             self.flg_div = self.flg_redir = self.flg_dest = False
  489.  
  490.  
  491. def follow_redirect(actress, parser):
  492.     alist = []
  493.  
  494.     while actress:
  495.         a = actress.pop(0)
  496.         verbose('ssw.a: {}'.format(a))
  497.         ssw_uri = 'http://sougouwiki.com/d/{}'.format(
  498.             urllib.parse.quote(a.encode('euc-jp'), 'euc-jp'))
  499.         verbose('ssw uri: {}'.format(ssw_uri))
  500.         html = open_uri(ssw_uri)
  501.         parser.__init__()
  502.         parser.feed(html)
  503.         a = '{}>{}'.format(a, parser.dest) if parser.dest else a
  504.         verbose('redirect: {}'.format(a))
  505.         alist.append(a)
  506.         if actress: time.sleep(3)
  507.  
  508.     return(alist)
  509.  
  510.  
  511. def check_missings():
  512.     '''未取得情報のチェック'''
  513.     missings = [m for m in ('release', 'title', 'maker', 'label', 'image_sm') if not SUMMARY[m]]
  514.     verbose('missings: {}'.format(missings))
  515.     if missings:
  516.         stderror('W', '取得できない情報がありました: {0}'.format(",".join(missings)))
  517.  
  518.  
  519. def format_wikitext_r(anum, astr):
  520.     '''ウィキテキストの作成 女優ページ用'''
  521.     wtextlist = []
  522.  
  523.     # 発売日
  524.     wtextlist.append('//{0[release]}'.format(SUMMARY))
  525.     # 自動修正があった場合のDMM上のタイトル (コメント)
  526.     if SUMMARY['title_dmm']:
  527.         wtextlist.append('//{0[title_dmm]} #検索用'.format(SUMMARY))
  528.     # タイトルおよびメーカー
  529.     titleline = '[[{0[title]}({1})>{0[uri]}]]'.format(
  530.         SUMMARY, SUMMARY['maker'] or SUMMARY['label'])
  531.     # シリーズ
  532.     if SUMMARY['series']:
  533.         titleline += ' [[(シリーズ一覧)>{0[series]}]]'.format(SUMMARY)
  534.     wtextlist.append(titleline)
  535.     # 画像
  536.     if SUMMARY['image_sm'] == SUMMARY['image_lg']:
  537.         wtextlist.append('{0[image_sm]}'.format(SUMMARY))
  538.     else:
  539.         wtextlist.append('[[{0[image_sm]}>{0[image_lg]}]]'.format(SUMMARY))
  540.     # 出演者
  541.     if anum > 1:
  542.         wtextlist.append('出演者:{0}'.format(astr))
  543.     # 追加カラム
  544.     if SUMMARY['extra']:
  545.         wtextlist.extend(SUMMARY['extra'])
  546.     # 備考
  547.     if SUMMARY['note']:
  548.         wtextlist.append(SUMMARY['note'])
  549.     wtextlist.append('')
  550.  
  551.     return wtextlist
  552.  
  553.  
  554. def format_wikitext_t(astr, dstr):
  555.     '''ウィキテキストの作成 table形式'''
  556.     wtext = ''
  557.  
  558.     # 品番
  559.     wtext += '|[[{0[pid]}>{0[uri]}]]'.format(SUMMARY)
  560.     # 画像
  561.     if SUMMARY['image_sm'] == SUMMARY['image_lg']:
  562.         wtext += '|{0[image_sm]}'.format(SUMMARY)
  563.     else:
  564.         wtext += '|[[{0[image_sm]}>{0[image_lg]}]]'.format(SUMMARY)
  565.     # サブタイトル
  566.     wtext += '|{0[subtitle]}'.format(SUMMARY)
  567.     # 出演者
  568.     wtext += '|{0}'.format(astr)
  569.     # 監督
  570.     wtext += '|{0}'.format(dstr)
  571.     # 発売日
  572.     wtext += '|{0[release]}'.format(SUMMARY).replace('.', '-')
  573.     # 追加カラム
  574.     if SUMMARY['extra']:
  575.         wtext += '|{}'.format('|'.join(SUMMARY['extra']))
  576.     # 備考
  577.     wtext += '|{0[note]}|'.format(SUMMARY)
  578.  
  579.     return wtext
  580.  
  581.  
  582. def main(param_tbl=0, param_subtitle='', param_series='', param_redir=False,
  583.          param_uri='', param_pid='', param_actress=(), param_num=0,
  584.          param_note='', param_extra=()):
  585.     '''主処理'''
  586.     global VERBOSE
  587.     global SUMMARY
  588.     global AUTOMODIFY
  589.     global AUTOSTRIP
  590.  
  591.     SUMMARY = {'uri':       '',
  592.                'release':   '',
  593.                'title':     '',
  594.                'title_dmm': '',
  595.                'subtitle':  '',
  596.                'actress':   [],
  597.                'director':  [],
  598.                'series':    '',
  599.                'maker':     '',
  600.                'label':     '',
  601.                'pid':       '',
  602.                'image_sm':  '',
  603.                'image_lg':  '',
  604.                'number':     0,
  605.                'note':      '',
  606.                'extra':    []}
  607.     tablefmt  = 0  # 1: table形式も作成, 2: table形式のみ作成
  608.     wikitext_r = []
  609.     wikitext_t = ''
  610.  
  611.     if __name__ != '__main__':
  612.         # モジュール呼び出しの場合継承したコマンドライン引数は無視
  613.         sys.argv = [sys.argv[0], param_uri]
  614.  
  615.     # コマンドライン引数の解釈
  616.     args = get_args()
  617.  
  618.     SUMMARY['uri']    = param_uri or args.uri
  619.     SUMMARY['number'] = param_num or args.number
  620.     SUMMARY['note']   = param_note or args.note
  621.     SUMMARY['extra']  = param_extra or args.extra
  622.  
  623.     add_actress = param_actress or args.actress
  624.     tablefmt    = param_tbl or args.table
  625.     follow_redir = param_redir or args.follow_redirect
  626.  
  627.     AUTOMODIFY = args.disable_modify_title
  628.     AUTOSTRIP  = args.disable_strip_oldname
  629.  
  630.  
  631.     # URIを開いて読み込む
  632.     html = open_uri(SUMMARY['uri'])
  633.     # HTMLParserが解析できない構文ミスの修正
  634.     html = sub(sp_wikis, html)
  635.  
  636.     # HTMLの解析
  637.     parser = DMMParser()
  638.     parser.feed(html)
  639.     verbose('SUMMARY: {}'.format(SUMMARY))
  640.  
  641.     SUMMARY['series'] = param_series or args.series or SUMMARY['series']
  642.  
  643.     # 品番の設定
  644.     SUMMARY['pid'] = param_pid or args.pid
  645.     if not SUMMARY['pid']:
  646.         # 未指定時の自動生成 (汎用)
  647.         pid, m = sub(sp_pid, p_cid.search(SUMMARY['uri']).group(1), True)
  648.         if m: SUMMARY['pid'] = pid.upper()
  649.     verbose('pid: ' + SUMMARY['pid'])
  650.  
  651.     # 既知の全出演者リストの作成
  652.     SUMMARY['actress'].extend(
  653.         filter(lambda a: not a in SUMMARY['actress'], add_actress))
  654.     if follow_redir:
  655.         follower = SswRedirectDest()
  656.         SUMMARY['actress'] = follow_redirect(SUMMARY['actress'], follower)
  657.     verbose('actress: {}'.format(SUMMARY['actress']))
  658.  
  659.     # 出演者文字列の作成
  660.     actsstr = "/".join('[[{0}]]'.format(p) for p in SUMMARY['actress'])
  661.     anum = len(SUMMARY['actress'])
  662.     if SUMMARY['number'] > anum:
  663.         actsstr += ' ほか計{0}名'.format(SUMMARY['number'])
  664.         anum = SUMMARY['number']
  665.  
  666.     # 監督文字列の作成
  667.     dirstr = "/".join(SUMMARY['director'])
  668.  
  669.     # table形式用副題の生成
  670.     SUMMARY['subtitle'] = param_subtitle or args.subtitle
  671.     if not SUMMARY['subtitle']:
  672.         SUMMARY['subtitle'] = \
  673.             re.sub(SUMMARY['series'], '', SUMMARY['title']).strip() \
  674.             if SUMMARY['series'] else SUMMARY['title']
  675.     verbose('subtitle: {}'.format(SUMMARY['subtitle']))
  676.  
  677.     # 未取得情報のチェック
  678.     if VERBOSE: check_missings()
  679.  
  680.     # ウィキテキストの作成
  681.     if tablefmt < 2:
  682.         wikitext_r = format_wikitext_r(anum, actsstr)
  683.         verbose('wikitext_r: {}'.format(wikitext_r))
  684.     if tablefmt:
  685.         wikitext_t = format_wikitext_t(actsstr, dirstr)
  686.         verbose('wikitext_t: {}'.format(wikitext_t))
  687.  
  688.     if __name__ != '__main__':
  689.         # モジュール呼び出しならタプルを返す。
  690.         return (SUMMARY['release'], SUMMARY['pid'], wikitext_r, wikitext_t)
  691.     else:
  692.         # 書き出す
  693.         print()
  694.         for t in wikitext_r + [wikitext_t]:
  695.             print(t)
  696.  
  697.     # キャッシュディレクトリの削除
  698.     if HTTPLIB2 and args.clear_cache: rmtree(CACHEDIR)
  699.  
  700.  
  701. if __name__ == '__main__':
  702.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement