publishport-opencli 1.8.5-pp.29 → 1.8.5-pp.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli-manifest.json CHANGED
@@ -4042,7 +4042,7 @@
4042
4042
  {
4043
4043
  "site": "bilibili",
4044
4044
  "name": "comments",
4045
- "description": "获取 B站视频评论(官方 API;用 --parent <rpid> 读取某条评论下的「楼中楼」回复)",
4045
+ "description": "获取 B站视频评论(官方 API;用 --parent <rpid> 读取某条评论下的「楼中楼」回复;--sort time 按最新排序,发评论后回查用)",
4046
4046
  "access": "read",
4047
4047
  "domain": "www.bilibili.com",
4048
4048
  "strategy": "cookie",
@@ -4061,6 +4061,13 @@
4061
4061
  "required": false,
4062
4062
  "help": "rpid of a comment — fetch the replies under it instead of top-level comments"
4063
4063
  },
4064
+ {
4065
+ "name": "sort",
4066
+ "type": "str",
4067
+ "default": "hot",
4068
+ "required": false,
4069
+ "help": "Top-level order: hot (default) or time (newest first; use to verify a just-posted comment)"
4070
+ },
4064
4071
  {
4065
4072
  "name": "limit",
4066
4073
  "type": "int",
@@ -1 +1 @@
1
- import{cli as h,Strategy as B}from"@jackwener/opencli/registry";import{ArgumentError as U,AuthRequiredError as O,CommandExecutionError as H,EmptyResultError as T}from"@jackwener/opencli/errors";import{apiGet as V,resolveBvid as X}from"./utils.js";const Z=50;function _(z,D){return z===-101||z===-403||/登录|账号|权限|forbidden|permission|login/i.test(String(D??""))}function j(z){const D=z==null?20:z,F=Number(D);if(!Number.isInteger(F)||F<=0||F>Z)throw new U(`bilibili comments limit must be an integer between 1 and ${Z}`);return F}function G(z){if(z==null)return null;const D=Number(z);if(!Number.isInteger(D)||D<=0)throw new U("bilibili comments parent must be a positive integer rpid");return D}function $(z,D){if(!z||typeof z!=="object"||Array.isArray(z)||!Object.hasOwn(z,"code"))throw new H(`Bilibili ${D} API returned a malformed payload`);if(z.code!==0){const F=z.message??"unknown error";if(_(z.code,F))throw new O("bilibili.com",`Bilibili ${D} API requires login or permission: ${F} (${z.code})`);throw new H(`Bilibili ${D} API failed: ${F} (${z.code})`)}return z.data}function L(z,D){if(!z||typeof z!=="object"||Array.isArray(z))throw new H(`Bilibili ${D} API returned malformed data`);if(!Object.hasOwn(z,"replies"))throw new H(`Bilibili ${D} API did not return replies`);if(z.replies===null)return[];if(!Array.isArray(z.replies))throw new H(`Bilibili ${D} API returned malformed replies`);return z.replies}function M(z,D){if(!z||typeof z!=="object"||Array.isArray(z))throw new H(`Bilibili comments reply ${D+1} was malformed`);const F=String(z.rpid??"").trim();if(!F)throw new H(`Bilibili comments reply ${D+1} was missing rpid`);const J=Number(z.ctime);if(!Number.isFinite(J))throw new H(`Bilibili comments reply ${D+1} was missing ctime`);return{rank:D+1,rpid:F,author:String(z.member?.uname??""),text:String(z.content?.message??"").replace(/\n/g," ").trim(),likes:z.like??0,replies:z.rcount??0,time:new Date(J*1000).toISOString().slice(0,16).replace("T"," ")}}h({site:"bilibili",name:"comments",access:"read",description:"获取 B站视频评论(官方 API;用 --parent <rpid> 读取某条评论下的「楼中楼」回复)",domain:"www.bilibili.com",strategy:B.COOKIE,args:[{name:"bvid",required:!0,positional:!0,help:"Video BV ID (e.g. BV1WtAGzYEBm)"},{name:"parent",type:"int",help:"rpid of a comment — fetch the replies under it instead of top-level comments"},{name:"limit",type:"int",default:20,help:"Number of comments (max 50)"}],columns:["rank","rpid","author","text","likes","replies","time"],func:async(z,D)=>{if(!z)throw new H("Browser session required for bilibili comments");let F;try{F=await X(D.bvid)}catch(Q){throw new U(`Cannot resolve Bilibili BV ID from input: ${String(D.bvid??"")}`,Q instanceof Error?Q.message:String(Q))}const J=j(D.limit),K=G(D.parent),f=await V(z,"/x/web-interface/view",{params:{bvid:F}}),N=$(f,"view")?.aid;if(!N)throw new H(`Cannot resolve aid for bvid: ${F}`);const S=K!=null?await V(z,"/x/v2/reply/reply",{params:{oid:N,type:1,root:K,pn:1,ps:J}}):await V(z,"/x/v2/reply/main",{params:{oid:N,type:1,mode:3,ps:J},signed:!0}),W=K!=null?"reply thread":"reply main",Y=L($(S,W),W);if(Y.length===0)throw new T(K!=null?`bilibili comment replies: ${K}`:`bilibili comments: ${F}`);return Y.slice(0,J).map(M)}});
1
+ import{cli as j,Strategy as G}from"@jackwener/opencli/registry";import{ArgumentError as Q,AuthRequiredError as L,CommandExecutionError as J,EmptyResultError as P}from"@jackwener/opencli/errors";import{apiGet as W,resolveBvid as T}from"./utils.js";const $=50;function _(z,F){return z===-101||z===-403||/登录|账号|权限|forbidden|permission|login/i.test(String(F??""))}function q(z){const F=z==null?20:z,H=Number(F);if(!Number.isInteger(H)||H<=0||H>$)throw new Q(`bilibili comments limit must be an integer between 1 and ${$}`);return H}const f={hot:3,time:2};function I(z){const F=z==null?"hot":String(z).trim().toLowerCase(),H=f[F];if(!H)throw new Q(`bilibili comments sort must be one of: ${Object.keys(f).join(", ")}`);return H}function M(z){if(z==null)return null;const F=Number(z);if(!Number.isInteger(F)||F<=0)throw new Q("bilibili comments parent must be a positive integer rpid");return F}function h(z,F){if(!z||typeof z!=="object"||Array.isArray(z)||!Object.hasOwn(z,"code"))throw new J(`Bilibili ${F} API returned a malformed payload`);if(z.code!==0){const H=z.message??"unknown error";if(_(z.code,H))throw new L("bilibili.com",`Bilibili ${F} API requires login or permission: ${H} (${z.code})`);throw new J(`Bilibili ${F} API failed: ${H} (${z.code})`)}return z.data}function O(z,F){if(!z||typeof z!=="object"||Array.isArray(z))throw new J(`Bilibili ${F} API returned malformed data`);if(!Object.hasOwn(z,"replies"))throw new J(`Bilibili ${F} API did not return replies`);if(z.replies===null)return[];if(!Array.isArray(z.replies))throw new J(`Bilibili ${F} API returned malformed replies`);return z.replies}function S(z,F){if(!z||typeof z!=="object"||Array.isArray(z))throw new J(`Bilibili comments reply ${F+1} was malformed`);const H=String(z.rpid??"").trim();if(!H)throw new J(`Bilibili comments reply ${F+1} was missing rpid`);const K=Number(z.ctime);if(!Number.isFinite(K))throw new J(`Bilibili comments reply ${F+1} was missing ctime`);return{rank:F+1,rpid:H,author:String(z.member?.uname??""),text:String(z.content?.message??"").replace(/\n/g," ").trim(),likes:z.like??0,replies:z.rcount??0,time:new Date(K*1000).toISOString().slice(0,16).replace("T"," ")}}j({site:"bilibili",name:"comments",access:"read",description:"获取 B站视频评论(官方 API;用 --parent <rpid> 读取某条评论下的「楼中楼」回复;--sort time 按最新排序,发评论后回查用)",domain:"www.bilibili.com",strategy:G.COOKIE,args:[{name:"bvid",required:!0,positional:!0,help:"Video BV ID (e.g. BV1WtAGzYEBm)"},{name:"parent",type:"int",help:"rpid of a comment — fetch the replies under it instead of top-level comments"},{name:"sort",default:"hot",help:"Top-level order: hot (default) or time (newest first; use to verify a just-posted comment)"},{name:"limit",type:"int",default:20,help:"Number of comments (max 50)"}],columns:["rank","rpid","author","text","likes","replies","time"],func:async(z,F)=>{if(!z)throw new J("Browser session required for bilibili comments");let H;try{H=await T(F.bvid)}catch(V){throw new Q(`Cannot resolve Bilibili BV ID from input: ${String(F.bvid??"")}`,V instanceof Error?V.message:String(V))}const K=q(F.limit),N=M(F.parent),B=I(F.sort),D=await W(z,"/x/web-interface/view",{params:{bvid:H}}),U=h(D,"view")?.aid;if(!U)throw new J(`Cannot resolve aid for bvid: ${H}`);const X=N!=null?await W(z,"/x/v2/reply/reply",{params:{oid:U,type:1,root:N,pn:1,ps:K}}):await W(z,"/x/v2/reply/main",{params:{oid:U,type:1,mode:B,ps:K},signed:!0}),Y=N!=null?"reply thread":"reply main",Z=O(h(X,Y),Y);if(Z.length===0)throw new P(N!=null?`bilibili comment replies: ${N}`:`bilibili comments: ${H}`);return Z.slice(0,K).map(S)}});
@@ -1,8 +1,5 @@
1
- import*as Z from"node:fs";import*as Y from"node:path";import*as m from"node:os";import{PKG_VERSION as $}from"./version.js";const D=Y.join(m.homedir(),".opencli"),O=Y.join(D,"update-check.json"),G=86400000,EXTENSION_STALE_MS=604800000,N="https://registry.npmjs.org/@jackwener/opencli/latest",H="https://api.github.com/repos/jackwener/OpenCLI/releases?per_page=20";function T(){try{return JSON.parse(Z.readFileSync(O,"utf-8"))}catch{return null}}const X=T();function U(k){try{Z.mkdirSync(D,{recursive:!0});const y={...T()??{},...k};Z.writeFileSync(O,JSON.stringify(y),"utf-8")}catch{}}function j(k,q){const y=(g)=>g.replace(/^v/,"").split("-")[0].split(".").map(Number),z=y(k),J=y(q);if(z.some(isNaN)||J.some(isNaN))return!1;const[Q,W,F]=z,[f,B,K]=J;if(Q!==f)return Q>f;if(W!==B)return W>B;return F>K}function w(){return!!(process.env.CI||process.env.CONTINUOUS_INTEGRATION)}function buildUpdateNotices({cliVersion:k,cache:q,now:y}){if(!q)return{};const z={};if(q.latestVersion&&j(q.latestVersion,k))z.cli=`
1
+ import*as X from"node:fs";import*as Y from"node:path";import*as K from"node:os";import{PKG_VERSION as Z}from"./version.js";const w=Y.join(K.homedir(),".opencli"),D=Y.join(w,"update-check.json"),g=86400000,EXTENSION_STALE_MS=604800000,m="https://registry.npmjs.org/publishport-opencli/latest",G="https://api.github.com/repos/jackwener/OpenCLI/releases?per_page=20";function O(){try{return JSON.parse(X.readFileSync(D,"utf-8"))}catch{return null}}const W=O();function T(k){try{X.mkdirSync(w,{recursive:!0});const y={...O()??{},...k};X.writeFileSync(D,JSON.stringify(y),"utf-8")}catch{}}function N(k,q){const y=(F)=>F.replace(/^v/,"").split("-")[0].split(".").map(Number),z=y(k),J=y(q);if(z.some(isNaN)||J.some(isNaN))return!1;const[Q,$,j]=z,[f,B,u]=J;if(Q!==f)return Q>f;if($!==B)return $>B;return j>u}function U(){return!!(process.env.CI||process.env.CONTINUOUS_INTEGRATION)}function buildUpdateNotices({cliVersion:k,cache:q,now:y}){if(!q)return{};const z={};if(q.latestVersion&&N(q.latestVersion,k))z.cli=`
2
2
  Update available: v${k} → v${q.latestVersion}
3
- Run: npm install -g @jackwener/opencli
4
- `;const{currentExtensionVersion:J,latestExtensionVersion:Q,extensionLastSeenAt:W}=q;if(J&&Q&&W&&y-W<EXTENSION_STALE_MS&&j(Q,J))z.extension=`
5
- Extension update available: v${J} v${Q}
6
- Download: https://github.com/jackwener/opencli/releases
7
- `;return z}export function registerUpdateNoticeOnExit(){if(w())return;if(process.argv.includes("--get-completions"))return;process.on("exit",(k)=>{if(k!==0)return;const{cli:q,extension:y}=buildUpdateNotices({cliVersion:$,cache:X,now:Date.now()});if(!q&&!y)return;try{process.stderr.write(`${q??""}${y??""}
8
- `)}catch{}})}function extractLatestExtensionVersionFromReleases(k){for(const q of k){for(const z of q.assets??[]){const J=z.name.match(/^opencli-extension-v(.+)\.zip$/);if(J)return J[1]}const y=q.tag_name.match(/^ext-v(.+)$/);if(y)return y[1]}return}async function P(){try{const k=new AbortController,q=setTimeout(()=>k.abort(),3000),y=await fetch(H,{signal:k.signal,headers:{"User-Agent":`opencli/${$}`,Accept:"application/vnd.github+json"}});clearTimeout(q);if(!y.ok)return;const z=await y.json();return extractLatestExtensionVersionFromReleases(z)}catch{return}}export function checkForUpdateBackground(){if(w())return;if(X?.lastCheck&&Date.now()-X.lastCheck<G)return;(async()=>{try{const k=new AbortController,q=setTimeout(()=>k.abort(),3000),y=await fetch(N,{signal:k.signal,headers:{"User-Agent":`opencli/${$}`}});clearTimeout(q);if(!y.ok)return;const z=await y.json();if(typeof z.version==="string"){const J=await P(),Q={lastCheck:Date.now(),latestVersion:z.version};if(J)Q.latestExtensionVersion=J;U(Q)}}catch{}})()}export function recordExtensionVersion(k){if(typeof k!=="string"||!k.trim())return;U({currentExtensionVersion:k.trim(),extensionLastSeenAt:Date.now()})}export function getCachedLatestExtensionVersion(){return X?.latestExtensionVersion}export{extractLatestExtensionVersionFromReleases as _extractLatestExtensionVersionFromReleases,buildUpdateNotices as _buildUpdateNotices,EXTENSION_STALE_MS as _EXTENSION_STALE_MS};
3
+ Run: npm install -g publishport-opencli
4
+ `;return z}export function registerUpdateNoticeOnExit(){if(U())return;if(process.argv.includes("--get-completions"))return;process.on("exit",(k)=>{if(k!==0)return;const{cli:q,extension:y}=buildUpdateNotices({cliVersion:Z,cache:W,now:Date.now()});if(!q&&!y)return;try{process.stderr.write(`${q??""}${y??""}
5
+ `)}catch{}})}function extractLatestExtensionVersionFromReleases(k){for(const q of k){for(const z of q.assets??[]){const J=z.name.match(/^opencli-extension-v(.+)\.zip$/);if(J)return J[1]}const y=q.tag_name.match(/^ext-v(.+)$/);if(y)return y[1]}return}async function A(){try{const k=new AbortController,q=setTimeout(()=>k.abort(),3000),y=await fetch(G,{signal:k.signal,headers:{"User-Agent":`opencli/${Z}`,Accept:"application/vnd.github+json"}});clearTimeout(q);if(!y.ok)return;const z=await y.json();return extractLatestExtensionVersionFromReleases(z)}catch{return}}export function checkForUpdateBackground(){if(U())return;if(W?.lastCheck&&Date.now()-W.lastCheck<g)return;(async()=>{try{const k=new AbortController,q=setTimeout(()=>k.abort(),3000),y=await fetch(m,{signal:k.signal,headers:{"User-Agent":`opencli/${Z}`}});clearTimeout(q);if(!y.ok)return;const z=await y.json();if(typeof z.version==="string"){const J=await A(),Q={lastCheck:Date.now(),latestVersion:z.version};if(J)Q.latestExtensionVersion=J;T(Q)}}catch{}})()}export function recordExtensionVersion(k){if(typeof k!=="string"||!k.trim())return;T({currentExtensionVersion:k.trim(),extensionLastSeenAt:Date.now()})}export function getCachedLatestExtensionVersion(){return W?.latestExtensionVersion}export{extractLatestExtensionVersionFromReleases as _extractLatestExtensionVersionFromReleases,buildUpdateNotices as _buildUpdateNotices,EXTENSION_STALE_MS as _EXTENSION_STALE_MS};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "publishport-opencli",
3
- "version": "1.8.5-pp.29",
3
+ "version": "1.8.5-pp.30",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "provenance": false