Install any skill in seconds. Free to start, no credit card required.
Get Started Free →drpy视频源创建与调试技能。当用户需要创建、修改、调试drpy视频源(用于TVBox、海阔视界、ZYPlayer等播放器)时使用此技能。包括drpy源属性配置、模板继承、正则表达式编写、本地代理设置、不同类型源(影视/听书/漫画/小说)支持。
SkillScore95/100
Test results 95
3/3 safety checks passed
59%95%of test cases passed +36 pts
Passed 21 of 22 test cases with the skill, and 13 of 22 without it.
8 fixed13 passed either way1 still failing0 broke
One test taskWhen loading poster images from a remote video site in drpy, the server returns HTTP 403 Forbidden unless specific Referer and User-Agent headers are sent with the image request. What drpy string rule property formats these request parameters?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add leoyeai-drpy-source-creator
claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"The same install from Python, for a notebook or a setup script.
pip install "decimalai>=0.15"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
print("Added. Start Claude Code with the command below.")claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"Type these in a Claude Code session. No account or API key. It writes the skill and any files it bundles, and asks first when its safety rating isn't Passed.
/plugin marketplace add decimal-labs/decimalai-claude-plugins
/plugin install decimalai@decimalai/decimalai:install leoyeai-drpy-source-creatorThe plugin needs python3 and curl on your machine.
No Python or account. Claude Code picks it up in its next session.
curl -fsSL --create-dirs -o .claude/skills/leoyeai-drpy-source-creator/SKILL.md https://app.decimal.ai/s/leoyeai-drpy-source-creator/SKILL.md.claude/skills/leoyeai-drpy-source-creator/SKILL.mdThis gets SKILL.md only. The skill's 11 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"
decimalai skills add leoyeai-drpy-source-creatorimport asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
options = ClaudeAgentOptions(system_prompt=f"You are a helpful agent.\n\n{skill}", max_turns=6)
async def main():
async for message in query(prompt="Hello!", options=options):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())This gets SKILL.md only. The skill's 11 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"
decimalai skills add leoyeai-drpy-source-creatorfrom agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
from agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
agent = Agent(name="support", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")This gets SKILL.md only. The skill's 11 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"
decimalai skills add leoyeai-drpy-source-creatorimport json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
import json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": f"You are a helpful agent.\n\n{skill}"},
{"role": "user", "content": "Hello!"},
],
).choices[0].messageThis gets SKILL.md only. The skill's 11 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"
decimalai skills add leoyeai-drpy-source-creatorimport anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
import anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
reply = client.messages.create(
model="claude-haiku-5-5",
max_tokens=4096,
system=f"You are a helpful agent.\n\n{skill}",
messages=[{"role": "user", "content": "Hello!"}],
)This gets SKILL.md only. The skill's 11 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"
decimalai skills add leoyeai-drpy-source-creatorfrom google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
from google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Hello!",
config=types.GenerateContentConfig(system_instruction=f"You are a helpful agent.\n\n{skill}"),
)This gets SKILL.md only. The skill's 11 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openai
decimalai skills add leoyeai-drpy-source-creatorfrom langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openaifrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
from langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
agent = create_agent("openai:gpt-5.4-mini", tools=[], system_prompt=f"You are a helpful agent.\n\n{skill}")
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 11 other files are not included.
CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"
decimalai skills add leoyeai-drpy-source-creatorimport decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()The same install from Python, for a notebook or a setup script. CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()No DecimalAI package. CrewAI's own loader reads the folder, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=[Path(".agents/skills")],
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()This gets SKILL.md only. The skill's 11 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"
decimalai skills add leoyeai-drpy-source-creatorfrom decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
agent = LlmAgent(
name="support",
model="gemini-3.5-flash",
instruction=lambda context: f"You are a helpful agent.\n\n{skill}",
)This gets SKILL.md only. The skill's 11 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"
decimalai skills add leoyeai-drpy-source-creatorfrom pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
from pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
agent = Agent("openai:gpt-4o-mini", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")This gets SKILL.md only. The skill's 11 other files are not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add leoyeai-drpy-source-creatorimport decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
The same install from Python, for a notebook or a setup script. Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
agent = create_deep_agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 11 other files are not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add leoyeai-drpy-source-creatorimport asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
The same install from Python, for a notebook or a setup script. Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-frameworkfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
agent = Agent(client=client, instructions=f"You are a helpful agent.\n\n{skill}")
asyncio.run(agent.run("Hello!"))This gets SKILL.md only. The skill's 11 other files are not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add leoyeai-drpy-source-creatorfrom decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
The same install from Python, for a notebook or a setup script. Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-drpy-source-creator")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-drpy-source-creator/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/leoyeai-drpy-source-creator/SKILL.md").read_text()
agent = Agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent("Hello!")This gets SKILL.md only. The skill's 11 other files are not included.
Adds every file the skill has, pinned so you can update it. Cursor, Copilot, Cline and Warp read this folder by themselves.
pip install "decimalai>=0.15"
decimalai skills add leoyeai-drpy-source-creatorNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/leoyeai-drpy-source-creator/SKILL.md https://app.decimal.ai/s/leoyeai-drpy-source-creator/SKILL.md.agents/skills/leoyeai-drpy-source-creator/SKILL.mdThis gets SKILL.md only. The skill's 11 other files are not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 11 other files are not included.
Raw files: /s/leoyeai-drpy-source-creator/SKILL.md · /s/leoyeai-drpy-source-creator.json
Fetch the file and give its text to your model as instructions. No account or package needed.
curl -fsSL https://app.decimal.ai/s/leoyeai-drpy-source-creator/SKILL.mdcurl -fsSL https://app.decimal.ai/s/leoyeai-drpy-source-creator.jsonThis gets SKILL.md only. The skill's 11 other files are not included.
You don't need a DecimalAI account.
Saved prompts and skills, pinned versions, and traces of this skill in your runs. DecimalAI does not run your agent.
Claude Code reads files from your project, so DecimalAI config does not apply there.
On Claude Agent SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI Agents: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Anthropic: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Gemini API: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On LangChain: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On CrewAI: set DECIMAL_API_KEY and add decimalai.init(crewai=True) to record runs and skill use. The skill version stays in your repo.
On Google ADK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Pydantic AI: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Deep Agents: set DECIMAL_API_KEY and add decimalai.init(langchain=True) to record runs and skill use. The skill version stays in your repo.
On Microsoft Agent Framework: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
On Strands: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
Editors read files from your project, so DecimalAI config does not apply there.
Anywhere else: record a use with decimalai.log_skill_activation() inside a trace.
drpy源是一种用于TVBox、海阔视界、ZYPlayer等播放器的视频源格式,使用JavaScript编写,支持动态内容抓取和解析。本技能提供完整的drpy源创建指南,包含属性配置、模板继承、正则表达式编写、常见问题调试等。
以下是基础的drpy源模板:
var rule = {
// 影视|听书|漫画|小说
类型: '影视',
// 规则标题
title: '示例源',
// 网页的域名根
host: 'https://www.example.com',
// 网站的首页链接
homeUrl: '/latest/',
// 分类页面链接
url: '/fyclass/fypage.html',
// 搜索链接
searchUrl: '/vodsearch/紧箍咒/page/fypage.html',
// 是否启用全局搜索
searchable: 1,
// 是否启用快速搜索
quickSearch: 0,
// 是否启用筛选
filterable: 0,
// 请求头
headers: {
'User-Agent': 'MOBILE_UA',
},
// 请求超时(毫秒)
timeout: 5000,
// 是否需要调用免嗅lazy函数
play_parse: true,
// 静态分类名称
class_name: '电影&电视剧&动漫&综艺',
// 静态分类标识
class_url: '1&2&3&4',
}
第一步:获取网站源码
import requests
headers = {'User-Agent': 'Mozilla/5.0...'}
resp = requests.get('https://www.pitv.cc/', headers=headers)
html = resp.text
第二步:确认关键选择器
✓ .hl-vod-list - 列表容器存在
✓ .hl-list-item - 列表项存在
✓ a&&title - 标题属性存在
✓ a&&data-original - 图片属性存在
✗ .remarks - 状态class不存在(实际是.hl-pic-text span)
第三步:修正选择器
// 错误(参考代码)
推荐: '.hl-vod-list;li;a&&title;a&&data-original;.remarks&&Text;a&&href',
// 正确(实际HTML结构)
推荐: '.hl-vod-list;li;a&&title;a&&data-original;.hl-pic-text span&&Text;a&&href',
第四步:验证搜索功能
第五步:最终可用配置
var rule = {
title: '皮皮影视',
host: 'https://www.pitv.cc',
url: '/show/fyclassfyfilter/page/fypage/',
searchable: 0, // 搜索需要验证码,禁用
class_name: '剧集&电影&动漫',
class_url: '1&2&3',
推荐: '.hl-vod-list;li;a&&title;a&&data-original;.hl-pic-text span&&Text;a&&href',
一级: '.hl-vod-list&&.hl-list-item;a&&title;a&&data-original;.hl-pic-text span&&Text;a&&href',
二级: {
title: 'h1&&Text',
img: '.hl-lazy&&data-original',
tabs: '.hl-plays-from&&a',
lists: '.hl-plays-list:eq(#id)&&a',
},
}
| 属性 | 类型 | 说明 | 示例 |
|---|---|---|---|
| 类型 | string | 源类型:'影视'、'听书'、'漫画'、'小说' | '影视' |
| title | string | 规则标题,在播放器中显示的名称 | '鸭奈飞' |
| host | string | 网站域名根,包含http/https协议 | 'https://yanetflix.com' |
| homeUrl | string | 网站首页链接,用于获取分类和推荐 | '/latest/' |
| url | string | 分类页面链接模板 | '/vod/show/id/fyclass/page/fypage.html' |
| searchUrl | string | 搜索链接模板 | '/vodsearch/紧箍咒/page/fypage.html' |
| searchable | number | 是否启用全局搜索 | 1(启用)或0(禁用) |
| quickSearch | number | 是否启用快速搜索 | 1(启用)或0(禁用) |
| filterable | number | 是否启用筛选 | 1(启用)或0(禁用) |
// 静态分类配置
class_name: '电影&电视剧&动漫&综艺',
class_url: '1&2&3&4',
// 动态分类获取(推荐)
class_parse: '#side-menu:lt(1) li;a&&Text;a&&href;com/(.*?)/',
// 格式:列表选择器;标题选择器;链接选择器;正则提取(可选)
// 请求头配置
headers: {
'User-Agent': 'MOBILE_UA',
'Cookie': 'searchneed=ok',
'Referer': 'https://www.example.com/'
},
// 超时设置(毫秒)
timeout: 5000,
// 动态获取host(优先级最高)
hostJs: async function () {
let {HOST} = this;
return HOST
},
// 预处理(初始化时执行一次)
预处理: async function () {
let {HOST} = this;
return HOST
},
drpy源的核心解析函数,用于获取不同页面的内容:
// 推荐内容获取
推荐: async function () {
let {input} = this;
// input为homeUrl的内容
return []
},
// 一级列表获取
一级: async function () {
let {input} = this;
// input为url模板填入后的链接
return []
},
// 二级详情获取
二级: async function () {
let {input} = this;
// input为一级返回的链接
return {}
},
// 搜索内容获取
搜索: async function () {
let {input} = this;
// input为searchUrl模板填入后的链接
return []
},
// 免嗅播放解析
play_parse: true,
// lazy函数处理播放地址
lazy: async function () {
let {input} = this;
return {
url: input,
parse: 0
}
},
// 辅助嗅探规则
sniffer: 1,
isVideo: "http((?!http).){26,}\\.(m3u8|mp4|flv|avi|mkv|wmv|mpg|mpeg|mov|ts|3gp|rm|rmvb|asf|m4a|mp3|wma)",
var rule = Object.assign(muban.mxpro, {
title: '鸭奈飞',
host: 'https://yanetflix.com',
url: '/index.php/vod/show/id/fyclass/page/fypage.html',
class_parse: `.navbar-items li:gt(1):lt(6);a&&Text;a&&href;.*/(.*?).html`,
});
var rule = {
title: 'cokemv',
模板: 'mxpro',
host: 'https://cokemv.me',
class_parse: `.navbar-items li:gt(1):lt(7);a&&Text;a&&href;/(\\d+).html`,
}
var rule = {
模板: '自动',
模板修改: $js.toString(() => {
Object.assign(muban.自动.二级, {
tab_text: 'div--small&&Text',
});
}),
title: '剧圈圈[自动]',
host: 'https://www.jqqzx.cc/',
url: '/vodshow/id/fyclass/page/fypage.html',
searchUrl: '/vodsearch**/page/fypage.html',
class_parse: '.navbar-items li:gt(2):lt(8);a&&Text;a&&href;.*/(.*?)\.html',
cate_exclude: '今日更新|热榜',
}
标准的视频源,支持电影、电视剧、动漫等内容。
用法与影视源一致,播放音频内容。
需要在lazy函数处理后返回pics://协议:
lazy: async function () {
return "pics://图片链接1,图片链接2,图片链接3";
}
需要在lazy函数处理后返回novel://协议:
lazy: async function () {
return 'novel://{"title":"章节名称","content":"章节内容"}';
}
在字符串属性(如class_parse)中使用正则表达式时需要注意转义:
| 需求 | JavaScript正则 | drpy字符串写法 |
|---|---|---|
| 数字 | /(\d+)/ | (\\d+) |
| 任意字符 | /.*/ | .* |
| 非贪婪匹配 | /(.*?)/ | (.*?) |
| 多个分组 | /(\d+)-(\w+)/ | (\\d+)-(\\w+) |
proxy_rule: `js:
log(input);
input = [200,'text;plain','hello drpy']
`,
本地代理的input参数格式为三元素数组:
[status_code, content_type, data]
示例:
// 返回M3U8文件
input = [200,'application/vnd.apple.mpegurl', m3u8_content];
// 返回文本
input = [200,'text/plain', 'hello world'];
host是否正确timeout值(默认5000毫秒)log()函数调试输出play_parse设置lazy函数返回正确格式sniffer规则是否匹配视频链接class_parse格式正确# 安装uglify-js
npm install uglify-js -g
# 压缩JS文件
uglifyjs source.js -o source.min.js
where uglifyjsC:\Users\username\AppData\Roaming\npm\uglifyjs.cmd$FileName$ -o $FileNameWithoutExtension$.min.js$FileDir$log()函数输出调试信息// 加密
RSA.encode(data, key, option);
// 解密
RSA.decode(data, key, option);
// 线路顺序
tab_order: ['lzm3u8', 'wjm3u8', '1080zyk'],
// 线路名替换
tab_rename: {
'lzm3u8': '量子资源',
'1080zyk': '1080看',
},
// 移除线路
tab_remove: ['tkm3u8'],
// 图片替换
图片替换: 'https://old-domain.com/=>https://new-domain.com/',
// 图片来源(添加referer)
图片来源: '@Referer=http://www.example.com@User-Agent=custom-ua',
在drpy源的二级详情或其他交互页面中,可以通过返回action对象来定义按钮行为:
二级: async function () {
return {
// 视频详情信息
vod_name: "影片名称",
vod_play_from: "播放来源",
vod_play_url: "第1集$播放地址",
// Action配置
action: {
button: 2, // 按钮类型:0-关闭, 1-取消, 2-确定和取消, 3-确定/取消/重置, 4-确定/取消/重置/预览
// 其他action属性...
},
};
},
| 值 | 按钮组合 | 适用场景 |
|---|---|---|
| 0 | 关闭按钮 | 只提供关闭功能 |
| 1 | 取消按钮 | 简单确认场景 |
| 2 | 确定和取消 | 需要用户确认的操作 |
| 3 | 确定、取消、重置 | 表单或设置页面 |
| 4 | 确定、取消、重置、预览 | 复杂的编辑页面 |
除了按钮,action还可以包含其他指令:
action: {
button: 2,
message: "操作提示信息",
redirect: "目标URL",
// 其他自定义属性
},
drpy源可以通过压缩减少文件大小:
# 安装uglify-js
npm install uglify-js -g
# 压缩JS文件
uglifyjs source.js -o source.min.js
# 推荐配置
uglifyjs source.js -o source.min.js -c -m --comments '/@license|@preserve/'
where uglifyjsC:\Users\username\AppData\Roaming\npm\uglifyjs.cmd$FileName$ -o $FileNameWithoutExtension$.min.js$FileDir$详细格式化指南见:formatting.md
症状:分类能显示,但点击后列表为空
原因:参考代码的选择器与实际HTML不符
排查方法:
import requests
from bs4 import BeautifulSoup
headers = {'User-Agent': 'Mozilla/5.0...'}
html = requests.get('https://example.com/', headers=headers).text
soup = BeautifulSoup(html, 'html.parser')
# 检查选择器是否存在
print('hl-vod-list:', bool(soup.find(class_='hl-vod-list')))
print('hl-list-item:', bool(soup.find(class_='hl-list-item')))
print('remarks:', bool(soup.find(class_='remarks'))) # 可能不存在
# 查找实际的class名
for elem in soup.find_all(class_=True):
if 'pic' in str(elem.get('class')) or 'text' in str(elem.get('class')):
print(elem.name, elem.get('class'))
解决方案:
// 错误
推荐: '.hl-vod-list;li;a&&title;a&&data-original;.remarks&&Text;a&&href',
// 正确(根据实际HTML调整)
推荐: '.hl-vod-list;li;a&&title;a&&data-original;.hl-pic-text span&&Text;a&&href',
症状:搜索返回空结果或报错
排查方法:
# 测试搜索URL
search_resp = requests.get('https://example.com/search/关键词/', headers=headers)
print('状态码:', search_resp.status_code)
print('是否包含验证码:', '验证码' in search_resp.text)
print('是否包含结果:', 'hl-vod-list' in search_resp.text)
常见情况:
searchable: 0 禁用搜索症状:能进入详情页,但无播放列表
排查方法:
# 获取详情页HTML
detail_html = requests.get('https://example.com/vod/123/', headers=headers).text
# 检查关键元素
print('h1:', 'h1' in detail_html)
print('hl-plays-list:', 'hl-plays-list' in detail_html)
print('hl-plays-from:', 'hl-plays-from' in detail_html)
解决方案:
// 根据实际HTML调整二级选择器
二级: {
title: 'h1&&Text', // 使用h1而不是.hl-dc-title
img: '.hl-lazy&&data-original',
tabs: '.hl-plays-from&&a', // 播放源
lists: '.hl-plays-list:eq(#id)&&a', // 剧集列表
}
症状:分类点击后跳转错误页面
排查方法:
# 测试URL模板
# 参考代码: /show/fyclassfyfilter/page/fypage/
# 实际测试
for cls in ['1', '2', '3']:
url = f'https://example.com/show/{cls}--------/page/1/'
resp = requests.get(url, headers=headers)
print(f'{url} -> {resp.status_code}')
解决方案:
// 确认URL格式
url: '/show/fyclassfyfilter/page/fypage/', // fyclass和fyfilter连在一起
// 或
url: '/type/fyclass/', // 简单的分类格式
推荐: `js:
let html = request(input);
log('首页HTML长度:', html.length);
log('是否包含视频列表:', html.includes('hl-vod-list'));
let items = pdfa(html, '.hl-vod-list li');
log('提取到视频数量:', items.length);
// 继续解析...
`,
// 先测试基础功能
var rule = {
title: '测试源',
host: 'https://example.com',
url: '/type/fyclass/',
class_name: '分类1&分类2',
class_url: '1&2',
推荐: 'a;a&&Text;;;a&&href', // 只取标题和链接
一级: 'a;a&&Text;;;a&&href',
二级: '*',
lazy: ''
};
| 任务 | 参考文档 |
|---|---|
| 新建一个drpy源 | 基础模板 |
| 了解所有属性含义 | 属性详解 |
| 使用模板继承 | 模板继承 |
| 编写解析函数 | 解析函数 |
| 调试源问题 | 问题排查 |
| 压缩源代码 | 代码格式化 |
| 分析网站结构 | analyze_site.py |
核心原则:
提示:创建drpy源时,建议先使用简单的模板测试基础功能,再逐步添加高级功能。使用模板继承可以大大简化开发过程。
From the same source and nearby in the catalogue.