aboutsummaryrefslogtreecommitdiffstats
path: root/gallery_dl/extractor/naverblog.py
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2025-07-31 01:22:07 -0400
committerLibravatarUnit 193 <unit193@unit193.net>2025-07-31 01:22:07 -0400
commitd9539f96cc7ac112b7d8faad022190fbbc88c745 (patch)
tree471249d60b9202c00d7d82abec8b296fc881292e /gallery_dl/extractor/naverblog.py
parent889fc15f272118bf277737b6fac29d3faeffc641 (diff)
parenta6e995c093de8aae2e91a0787281bb34c0b871eb (diff)
Update upstream source from tag 'upstream/1.30.2'
Update to upstream version '1.30.2' with Debian dir f0dcd28a671f8600479182ff128e05ba8904a0d8
Diffstat (limited to 'gallery_dl/extractor/naverblog.py')
-rw-r--r--gallery_dl/extractor/naverblog.py173
1 files changed, 173 insertions, 0 deletions
diff --git a/gallery_dl/extractor/naverblog.py b/gallery_dl/extractor/naverblog.py
new file mode 100644
index 0000000..302cb63
--- /dev/null
+++ b/gallery_dl/extractor/naverblog.py
@@ -0,0 +1,173 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2019-2025 Mike Fährmann
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+"""Extractors for https://blog.naver.com/"""
+
+from .common import GalleryExtractor, Extractor, Message
+from .. import text, util
+import datetime
+import time
+
+
+class NaverBlogBase():
+ """Base class for blog.naver.com extractors"""
+ category = "naver-blog"
+ root = "https://blog.naver.com"
+
+
+class NaverBlogPostExtractor(NaverBlogBase, GalleryExtractor):
+ """Extractor for blog posts on blog.naver.com"""
+ subcategory = "post"
+ filename_fmt = "{num:>03}.{extension}"
+ directory_fmt = ("{category}", "{blog[user]} {blog[id]}",
+ "{post[date]:%Y-%m-%d} {post[title]}")
+ archive_fmt = "{blog[id]}_{post[num]}_{num}"
+ pattern = (r"(?:https?://)?blog\.naver\.com/"
+ r"(?:PostView\.n(?:aver|hn)\?blogId=(\w+)&logNo=(\d+)|"
+ r"(\w+)/(\d+)/?$)")
+ example = "https://blog.naver.com/BLOGID/12345"
+
+ def __init__(self, match):
+ if blog_id := match[1]:
+ self.blog_id = blog_id
+ self.post_id = match[2]
+ else:
+ self.blog_id = match[3]
+ self.post_id = match[4]
+
+ url = (f"{self.root}/PostView.nhn"
+ f"?blogId={self.blog_id}&logNo={self.post_id}")
+ GalleryExtractor.__init__(self, match, url)
+
+ def metadata(self, page):
+ extr = text.extract_from(page)
+ data = {
+ "post": {
+ "title" : text.unescape(extr(
+ '"og:title" content="', '"')),
+ "description": text.unescape(extr(
+ '"og:description" content="', '"')).replace("&nbsp;", " "),
+ "num" : text.parse_int(self.post_id),
+ },
+ "blog": {
+ "id" : self.blog_id,
+ "num" : text.parse_int(extr("var blogNo = '", "'")),
+ "user" : extr("var nickName = '", "'"),
+ },
+ }
+
+ data["post"]["date"] = self._parse_datetime(
+ extr('se_publishDate pcol2">', '<') or
+ extr('_postAddDate">', '<'))
+
+ return data
+
+ def _parse_datetime(self, date_string):
+ if "전" in date_string:
+ ts = time.gmtime()
+ return datetime.datetime(ts.tm_year, ts.tm_mon, ts.tm_mday)
+ return text.parse_datetime(date_string, "%Y. %m. %d. %H:%M")
+
+ def images(self, page):
+ files = []
+ self._extract_images(files, page)
+ if self.config("videos", True):
+ self._extract_videos(files, page)
+ return files
+
+ def _extract_images(self, files, page):
+ for url in text.extract_iter(page, 'data-lazy-src="', '"'):
+ url = url.replace("://post", "://blog", 1).partition("?")[0]
+ if "\ufffd" in text.unquote(url):
+ url = text.unquote(url, encoding="EUC-KR")
+ files.append((url, None))
+
+ def _extract_videos(self, files, page):
+ for module in text.extract_iter(page, " data-module='", "'></"):
+ if '"v2_video"' not in module:
+ continue
+ media = util.json_loads(module)["data"]
+ try:
+ self._extract_media(files, media)
+ except Exception as exc:
+ self.log.warning("%s: Failed to extract video '%s' (%s: %s)",
+ self.post_id, media.get("vid"),
+ exc.__class__.__name__, exc)
+
+ def _extract_media(self, files, media):
+ url = ("https://apis.naver.com/rmcnmv/rmcnmv/vod/play/v2.0/" +
+ media["vid"])
+ params = {
+ "key" : media["inkey"],
+ "sid" : "2",
+ # "pid": "00000000-0000-0000-0000-000000000000",
+ "nonce": int(time.time()),
+ "devt" : "html5_pc",
+ "prv" : "N",
+ "aup" : "N",
+ "stpb" : "N",
+ "cpl" : "ko_KR",
+ "providerEnv": "real",
+ "adt" : "glad",
+ "lc" : "ko_KR",
+ }
+ data = self.request_json(url, params=params)
+ video = max(data["videos"]["list"],
+ key=lambda v: v.get("size") or 0)
+ files.append((video["source"], video))
+
+
+class NaverBlogBlogExtractor(NaverBlogBase, Extractor):
+ """Extractor for a user's blog on blog.naver.com"""
+ subcategory = "blog"
+ categorytransfer = True
+ pattern = (r"(?:https?://)?blog\.naver\.com/"
+ r"(?:PostList\.n(?:aver|hn)\?(?:[^&#]+&)*blogId=([^&#]+)|"
+ r"(\w+)/?$)")
+ example = "https://blog.naver.com/BLOGID"
+
+ def __init__(self, match):
+ Extractor.__init__(self, match)
+ self.blog_id = match[1] or match[2]
+
+ def items(self):
+ # fetch first post number
+ url = f"{self.root}/PostList.nhn?blogId={self.blog_id}"
+ post_num = text.extr(
+ self.request(url).text, 'gnFirstLogNo = "', '"',
+ )
+
+ # setup params for API calls
+ url = f"{self.root}/PostViewBottomTitleListAsync.nhn"
+ params = {
+ "blogId" : self.blog_id,
+ "logNo" : post_num or "0",
+ "viewDate" : "",
+ "categoryNo" : "",
+ "parentCategoryNo" : "",
+ "showNextPage" : "true",
+ "showPreviousPage" : "false",
+ "sortDateInMilli" : "",
+ "isThumbnailViewType": "false",
+ "countPerPage" : "",
+ }
+
+ # loop over all posts
+ while True:
+ data = self.request_json(url, params=params)
+
+ for post in data["postList"]:
+ post["url"] = (f"{self.root}/PostView.nhn?blogId="
+ f"{self.blog_id}&logNo={post['logNo']}")
+ post["_extractor"] = NaverBlogPostExtractor
+ yield Message.Queue, post["url"], post
+
+ if not data["hasNextPage"]:
+ return
+ params["logNo"] = data["nextIndexLogNo"]
+ params["sortDateInMilli"] = data["nextIndexSortDate"]