#!/usr/bin/env python3
"""한국저작권위원회 판례를 수집해 프로젝트용 후보 JSONL을 만든다.
공식 목록 전체를 먼저 수집한 뒤 제목 기반 후보의 상세 페이지에서 국내 사건번호와
판시 내용을 확인한다. 네트워크 결과는 ``--cache-dir`` 아래에 캐시하므로 중단 후 다시
실행해도 이미 받은 페이지를 재요청하지 않는다.
"""
from __future__ import annotations
import argparse
import html
import json
import re
import subprocess
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
from urllib.parse import urljoin
from urllib.parse import urlencode, urlparse
import openpyxl
BASE = "https://www.copyright.or.kr/information-materials/trend/precedents/"
LIST_URL = urljoin(BASE, "list.do?pageIndex={page}")
VIEW_URL = urljoin(BASE, "view.do?brdctsno={board_id}")
USER_AGENT = "Mozilla/5.0 (compatible; O2O-Precedent-Research/1.0)"
CASE_RE = re.compile(
r"(?]*title="상세보기"[^>]*>'
r"(.*?)\s*\s*
(\d{4}-\d{2}-\d{2}) | ",
re.S,
)
# 제목에서 하나라도 발견되면 상세 검토 대상으로 삼는다. 프로젝트 범위는 자서전과
# 출판물의 본문·구조·인용·저작인격권 및 부속 시각/음성 자산이다.
TITLE_TERMS = (
"어문", "문학", "소설", "수필", "시집", "시인", "가사", "도서", "서적",
"출판", "저서", "저술", "기사", "뉴스", "신문", "잡지", "논문", "보고서",
"교재", "교과서", "문제집", "시험문제", "시험지", "수험서", "책자", "학습지",
"편집저작물", "제안서", "설명문", "상세페이지", "사전", "백과", "번역",
"대본", "각본", "시나리오", "스토리", "줄거리", "캐릭터", "편지", "일기",
"이메일", "블로그", "게시글", "SNS", "웹툰", "만화", "문구", "제호", "제목",
"강연", "설교", "폰트", "편집", "요약", "표절", "인용", "공정이용",
"공정 이용", "실질적 유사", "의거", "아이디어", "창작성", "성명표시",
"동일성유지", "공표권", "2차적저작물", "사진", "이미지", "그림", "표지",
"음악", "음원", "노래", "오디오북",
)
WORK_TYPE_TERMS = {
"literary": (
"어문", "문학", "소설", "수필", "시집", "시인", "가사", "도서", "서적",
"출판", "저서", "저술", "기사", "뉴스", "신문", "잡지", "논문", "보고서",
"교재", "교과서", "문제집", "시험문제", "시험지", "수험서", "책자", "학습지",
"편집저작물", "제안서", "설명문", "상세페이지", "사전", "백과", "번역",
"대본", "각본", "시나리오", "스토리", "줄거리", "편지", "일기", "이메일",
"블로그", "게시글", "강연", "설교", "요약",
),
"visual": ("사진", "이미지", "그림", "미술", "캐릭터", "만화", "웹툰", "표지"),
"musical": ("음악", "음원", "노래", "가요", "작곡", "오디오북"),
}
TAG_TERMS = {
"reproduction": (
"복제", "베끼", "표절", "무단 사용", "무단사용", "도용", "저작권 침해",
"저작권침해", "저작재산권 침해", "저작재산권침해", "실질적 유사",
),
"derivative_work": ("2차적저작물", "이차적저작물", "번역", "각색", "변형", "요약"),
"public_transmission": ("공중송신", "전송", "게시", "업로드", "온라인", "인터넷"),
"distribution": ("배포", "판매", "발행", "출판"),
"publication": ("공표", "미공표", "저작인격권"),
"attribution": ("성명표시", "성명 표시", "저작자 표시", "저작인격권"),
"integrity": ("동일성유지", "동일성 유지", "저작인격권"),
"citation_missing": ("인용", "출처표시", "출처 표시"),
"false_authorship": ("자기 저작", "본인 저작", "저작자 아닌", "대필"),
}
CRITERIA_TERMS = (
"실질적 유사성", "의거관계", "의거 관계", "접근 가능성", "보호되는 표현",
"창작적 표현", "창작성", "아이디어와 표현", "공정이용", "공정 이용", "정당한 인용",
"인용 요건", "저작물성", "2차적저작물", "저작인격권", "성명표시권",
"동일성유지권", "공표권",
)
def clean_html(value: str) -> str:
value = re.sub(r"