Commit 53c4ab68 authored by Javinator9889's avatar Javinator9889 🎼

Merge branch 'design' into 'master'

Design

See merge request !1
parents cd742496 d16dce06
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">
<option name="requirementsPath" value="E:\Nextcloud\Programming\YouTubeMDBot\App\requirements.txt" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData">
<serverData>
<paths name="Copy of project-level server 'Casa' (1)">
<serverdata>
<mappings>
<mapping local="$PROJECT_DIR$" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
</component>
</project>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="W391" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N802" />
<option value="N803" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="urlencode.urlencoder" />
</list>
</option>
</inspection_tool>
</profile>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6.1 (C:\Users\Javier Alonso Silva\AppData\Local\Programs\Python\Python36\python.exe)" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/App.iml" filepath="$PROJECT_DIR$/.idea/App.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="ecb85847-acff-4336-b3d7-4f5563aac01d" name="Default" comment="" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="CoverageDataManager">
<SUITE FILE_PATH="coverage/App$application.coverage" NAME="application Coverage Results" MODIFIED="1529336246883" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
</component>
<component name="FileEditorManager">
<leaf>
<file leaf-file-name="application.py" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/application.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-51">
<caret line="22" column="28" lean-forward="true" selection-start-line="22" selection-start-column="28" selection-end-line="22" selection-end-column="28" />
<folding>
<element signature="e#0#46#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="__init__.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/upgrader/__init__.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="170">
<caret line="10" selection-start-line="10" selection-end-line="10" />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="__init__.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/out/__init__.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="374">
<caret line="22" selection-start-line="22" selection-end-line="22" />
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Setup Script" />
<option value="Python Script" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/out/__init__.py" />
<option value="$PROJECT_DIR$/requirements.txt" />
<option value="$PROJECT_DIR$/upgrader/__init__.py" />
<option value="$PROJECT_DIR$/application.py" />
</list>
</option>
</component>
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsGulpfileManager">
<detection-done>true</detection-done>
<sorting>DEFINITION_ORDER</sorting>
</component>
<component name="NodePackageJsonFileManager">
<packageJsonPaths />
</component>
<component name="ProjectFrameBounds" extendedState="7">
<option name="x" value="-8" />
<option name="width" value="977" />
<option name="height" value="1038" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" />
</component>
<component name="ProjectView">
<navigator proportions="" version="1">
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="App" type="b2602c69:ProjectViewProjectNode" />
<item name="App" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="App" type="b2602c69:ProjectViewProjectNode" />
<item name="App" type="462c0819:PsiDirectoryNode" />
<item name="out" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="App" type="b2602c69:ProjectViewProjectNode" />
<item name="App" type="462c0819:PsiDirectoryNode" />
<item name="upgrader" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="Scope" />
</panes>
</component>
<component name="PropertiesComponent">
<property name="WebServerToolWindowFactoryState" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/requirements.txt" />
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyIntegratedToolsModulesConfigurable" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager">
<configuration name="application" type="PythonConfigurationType" factoryName="Python" temporary="true">
<module name="App" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/application.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.application" />
</list>
</recent_temporary>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="ecb85847-acff-4336-b3d7-4f5563aac01d" name="Default" comment="" />
<created>1529335044449</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1529335044449</updated>
</task>
<task id="LOCAL-00001" summary="First commit of the application - created methods for main and first setup">
<created>1529336000478</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1529336000478</updated>
</task>
<task id="LOCAL-00002" summary="Packages and cPrint method - pip upgrader also included">
<created>1529341560151</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1529341560151</updated>
</task>
<option name="localTasksCounter" value="3" />
<servers />
</component>
<component name="ToolWindowManager">
<frame x="-7" y="-7" width="1550" height="838" extended-state="6" />
<editor active="true" />
<layout>
<window_info anchor="bottom" id="TODO" order="12" />
<window_info anchor="bottom" id="Event Log" order="3" side_tool="true" />
<window_info anchor="bottom" id="Database Changes" order="2" show_stripe_button="false" />
<window_info anchor="bottom" id="Run" order="8" weight="0.32965517" />
<window_info anchor="bottom" id="Version Control" order="1" />
<window_info anchor="bottom" id="Python Console" order="5" />
<window_info anchor="bottom" id="Terminal" order="4" />
<window_info anchor="right" id="Remote Host" order="2" />
<window_info active="true" content_ui="combo" id="Project" order="1" visible="true" weight="0.26367188" />
<window_info anchor="bottom" id="Docker" order="0" show_stripe_button="false" />
<window_info anchor="right" id="Database" order="0" />
<window_info anchor="right" id="SciView" order="1" />
<window_info id="Structure" order="2" side_tool="true" weight="0.25" />
<window_info anchor="bottom" id="Debug" order="9" weight="0.4" />
<window_info id="Favorites" order="0" side_tool="true" />
<window_info anchor="bottom" id="Find" order="7" />
<window_info anchor="right" id="Commander" order="3" weight="0.4" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="5" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="11" weight="0.4" />
<window_info anchor="right" id="Ant Build" order="4" weight="0.25" />
<window_info anchor="bottom" id="Message" order="6" />
<window_info anchor="bottom" id="Cvs" order="10" weight="0.25" />
</layout>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="First commit of the application - created methods for main and first setup" />
<MESSAGE value="Packages and cPrint method - pip upgrader also included" />
<option name="LAST_COMMIT_MESSAGE" value="Packages and cPrint method - pip upgrader also included" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<option name="time" value="1" />
</breakpoint-manager>
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/app_data.dict">
<provider selected="true" editor-type-id="text-editor">
<state>
<caret column="38" lean-forward="true" selection-start-column="38" selection-end-column="38" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/setup.py">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/requirements.txt">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="17">
<caret line="1" column="19" selection-start-line="1" selection-start-column="19" selection-end-line="1" selection-end-column="19" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/out/__init__.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="374">
<caret line="22" selection-start-line="22" selection-end-line="22" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/upgrader/__init__.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="170">
<caret line="10" selection-start-line="10" selection-end-line="10" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/application.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-51">
<caret line="22" column="28" lean-forward="true" selection-start-line="22" selection-start-column="28" selection-end-line="22" selection-end-column="28" />
<folding>
<element signature="e#0#46#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
</project>
\ No newline at end of file
from argparse import ArgumentParser, Namespace
from .out import cPrint, Colors
from .upgrader import PiPUpgrader
def main(arguments: Namespace):
from os import path
import pickle
token = arguments.token
youtube_api_key = arguments.youtube
creator_id = arguments.creator
must_show_version = arguments.version
if must_show_version:
print("Version")
exit(0)
if not path.exists("app_data.dict"):
if not token:
raise ValueError("You must add token at least the first time you execute this app")
elif not youtube_api_key:
raise ValueError("You must include the YouTube API Key at least the first time you execute this app")
elif not creator_id:
raise ValueError("You must include the creator ID (Telegram) at least the first time you execute this app")
else:
with open("app_data.dict", "wb") as app_data_file:
app_data = {"TOKEN": token,
"YT_API": youtube_api_key,
"CREATOR_ID": creator_id}
pickle.dump(app_data, app_data_file, pickle.HIGHEST_PROTOCOL)
else:
cPrint("Initializing bot...", Colors.GREEN)
cPrint("Looking for packages updates...", Colors.GREEN)
upgrader = PiPUpgrader("requirements.txt")
upgrader.upgradePackages()
cPrint("Obtaining values...", Colors.GREEN)
with open("app_data.dict", "rb") as app_data_file:
app_data = pickle.load(app_data_file)
from telegram.ext import Updater
updater = Updater(token=app_data["TOKEN"], workers=50)
dispatcher = updater.dispatcher
import logging
logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.DEBUG)
updater.start_polling(poll_interval=5, timeout=60)
if __name__ == '__main__':
args = ArgumentParser()
args.add_argument("-t",
"--token",
help="Telegram token obtained via BotFather",
type=str)
args.add_argument("-y",
"--youtube",
help="YouTube API Key",
type=str)
args.add_argument("-c",
"--creator",
help="Telegram ID of the creator",
type=int)
args.add_argument("-v",
"--version",
help="Application version",
action="store_true")
main(args.parse_args())
class Colors:
RED = "red"
BLUE = "blue"
GREEN = "green"
WARNING = "warning"
FAIL = "fail"
BOLD = "bold"
UNDERLINE = "underline"
RESET_ALL = "reset_all"
class OutputColors:
colors = {Colors.RED: '\033[95m',
Colors.BLUE: '\033[94m',
Colors.GREEN: '\033[92m',
Colors.WARNING: '\033[93m',
Colors.FAIL: '\033[91m',
Colors.BOLD: '\033[1m',
Colors.UNDERLINE: '\033[4m',
Colors.RESET_ALL: '\033[0m'}
def cPrint(text: str, color: Colors = None):
colors = OutputColors.colors
if color is None:
color = colors[Colors.RESET_ALL]
print(colors[color] + text + colors[Colors.RESET_ALL])
pip
python-telegram-bot
class PiPUpgrader:
def __init__(self, file: str):
self.__file = file
def upgradePackages(self):
import subprocess
with open(self.__file, 'r') as f:
requirements = f.read().splitlines()
for requirement in requirements:
subprocess.run(("pip install -U " + requirement).split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="762" height="399">
<defs id="dmw_defs" >
<svg id="fk_sym" viewBox="0 0 48.665 48.665" style="enable-background:new 0 0 48.665 48.665;" >
<g>
<path d="M40.332,31.592c-2.377,0-4.515,1-6.033,2.598l-17.737-8.686c0.061-0.406,0.103-0.82,0.103-1.246 c0-0.414-0.04-0.818-0.098-1.215l17.711-8.589c1.519,1.609,3.666,2.619,6.054,2.619c4.603,0,8.333-3.731,8.333-8.333 c0-4.603-3.73-8.333-8.333-8.333s-8.333,3.73-8.333,8.333c0,0.414,0.04,0.817,0.098,1.215l-17.709,8.589 c-1.519-1.609-3.666-2.619-6.054-2.619C3.73,15.925,0,19.656,0,24.258c0,4.603,3.73,8.333,8.333,8.333 c2.377,0,4.515-1,6.033-2.596l17.736,8.685c-0.062,0.406-0.104,0.82-0.104,1.245c0,4.604,3.73,8.333,8.333,8.333 s8.333-3.729,8.333-8.333C48.665,35.322,44.935,31.592,40.332,31.592z" fill="#13bf3b"/>
</g>
</svg>
<svg id="pk_sym" viewBox="0 0 480.509 480.509" style="enable-background:new 0 0 480.509 480.509;" >
<g>
<path d="M418.119,331.046c4.094,4.374,7.766,8.186,10.996,11.416c3.237,3.238,6.714,6.376,10.427,9.422 c3.71,3.042,6.427,4.568,8.135,4.568c3.241,0,9.517-4.661,18.843-13.99c9.328-9.321,13.989-15.604,13.989-18.842 c0-1.523-2.714-5.421-8.138-11.704c-5.421-6.276-12.364-13.702-20.838-22.271c-8.473-8.565-16.703-16.744-24.694-24.55 c-8.001-7.81-15.8-15.373-23.417-22.703c-7.611-7.327-11.992-11.56-13.135-12.703c-1.902-1.902-4.093-2.853-6.563-2.853 c-3.237,0-9.521,4.661-18.843,13.988c-9.328,9.322-13.989,15.605-13.989,18.843c0,1.711,1.522,4.421,4.568,8.138 c3.046,3.71,6.188,7.187,9.421,10.424c3.23,3.23,7.047,6.899,11.42,10.992c4.377,4.093,6.848,6.423,7.423,6.995l-27.408,27.404 L254.954,222.268c24.94-33.498,37.408-68.236,37.408-104.211c0-31.024-9.761-56.293-29.263-75.801 c-19.512-19.511-44.778-29.265-75.805-29.265c-30.454,0-60.244,9.042-89.363,27.119c-29.121,18.083-52.727,41.686-70.808,70.808 C9.042,140.038,0,169.828,0,200.28c0,31.029,9.753,56.286,29.265,75.803c19.511,19.517,44.777,29.27,75.801,29.27 c35.976,0,70.71-12.467,104.212-37.407l191.574,191.579c5.332,5.328,11.796,7.994,19.417,7.994c7.991,0,15.704-3.72,23.12-11.14 c7.426-7.426,11.143-15.129,11.143-23.127c0-7.617-2.666-14.092-7.994-19.417l-62.811-62.811l27.405-27.404 C411.699,324.195,414.033,326.666,418.119,331.046z M221.556,161.458c-10.656,10.657-23.601,15.987-38.828,15.987 c-7.996,0-15.896-1.812-23.7-5.43c3.617,7.808,5.426,15.706,5.426,23.7c0,15.229-5.327,28.171-15.987,38.828 c-10.66,10.655-23.606,15.986-38.831,15.986c-15.227,0-28.168-5.325-38.828-15.986c-10.657-10.657-15.987-23.599-15.987-38.828 c0-15.227,5.327-28.171,15.987-38.828C81.464,146.23,94.409,140.9,109.636,140.9c7.992,0,15.893,1.809,23.695,5.424 c-3.616-7.804-5.424-15.706-5.424-23.699c0-15.227,5.327-28.171,15.987-38.828c10.66-10.657,23.604-15.987,38.831-15.987 c15.227,0,28.171,5.327,38.828,15.987c10.657,10.66,15.987,23.601,15.987,38.828C237.539,137.852,232.209,150.797,221.556,161.458z " fill="#ff8345"/>
</g>
</svg>
<svg id="uk_sym" viewBox="0 0 490 490" style="enable-background:new 0 0 490 490;" >
<g>
<polygon points="236.99,11.41 0,246.348 236.99,478.678 236.99,350.609 129.864,245 236.99,139.391 " fill="#0064fb"/>
<polygon points="253.01,478.59 490,243.651 253.01,11.322 253.01,139.391 360.136,245 253.01,350.609 " fill="#0064fb"/>
</g>
</svg>
<svg id="link_sym" viewBox="0 0 1000 900" style="enable-background:new 0 0 1000 900;" >
<g>
<path fill="black" d="M660.224 422.656c6.976 16.192-0.512 35.008-16.768 42.048-16.128 6.976-34.944-0.448-41.984-16.768-8.448-19.776-20.736-37.696-36.224-53.248-64.64-64.64-177.344-64.64-241.92 0l-145.216 145.28c-66.688 66.688-66.688 175.232 0 241.984 66.688 66.688 175.104 66.752 241.92 0l92.8-92.864c12.48-12.48 32.768-12.48 45.248 0s12.48 32.768 0 45.248l-92.8 92.864c-91.648 91.648-240.832 91.52-332.416 0-91.712-91.648-91.712-240.832 0-332.48l145.216-145.28c44.352-44.416 103.424-68.864 166.272-68.864s121.792 24.448 166.208 68.864c21.248 21.312 38.016 45.952 49.664 73.216zM891.136 401.344l-145.216 145.216c-88.768 88.832-243.712 88.832-332.416 0-21.312-21.312-38.080-45.952-49.728-73.216-7.040-16.256 0.448-35.072 16.704-42.048 16.064-6.784 35.008 0.512 41.984 16.768 8.512 19.776 20.8 37.696 36.288 53.248 64.64 64.64 177.344 64.64 241.92 0l145.216-145.216c66.688-66.688 66.688-175.232 0-241.984-66.752-66.624-175.168-66.688-241.92 0l-92.8 92.864c-12.48 12.48-32.768 12.48-45.248 0s-12.48-32.768 0-45.248l92.8-92.864c45.824-45.824 105.984-68.736 166.208-68.736s120.448 22.912 166.272 68.736c91.584 91.648 91.584 240.768-0.064 332.48z" />
</g>
</svg>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath1_0_">
<rect x="0" y="0" width="170" height="110" />
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath4_0_">
<rect x="0" y="0" width="170" height="110" />
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath3_0_">
<rect x="0" y="0" width="170" height="110" />
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath6_0_">
<rect x="0" y="0" width="170" height="110" />
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath5_0_">
<rect x="0" y="0" width="170" height="110" />
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath2_0_">
<rect x="0" y="0" width="170" height="110" />
</clipPath>
</defs>
<g stroke-linecap="butt" >
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-dasharray="8,8" stroke-width="1" d="M212 343 L258 343" />
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-width="1" d="M305 343 L258 343" />
<path stroke-dasharray="none" d="M212.0 337.0 L224.0 343.0 L212.0 349.0" fill="none" stroke-width="1" stroke-opacity="1.0" stroke="rgb(0,0,0)" />
<path stroke-dasharray="none" d="M305.0 349.0 L293.0 343.0 L305.0 337.0" fill="none" stroke-width="1" stroke-opacity="1.0" stroke="rgb(0,0,0)" />
</g>
<g stroke-linecap="butt" >
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-dasharray="8,8" stroke-width="1" d="M475 345 L526 345" />
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-width="1" d="M578 345 L526 345" />
</g>
<g stroke-linecap="butt" >
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-dasharray="8,8" stroke-width="1" d="M302 85 L255 85" />
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-width="1" d="M209 85 L255 85" />
</g>
<g stroke-linecap="butt" >
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-dasharray="8,8" stroke-width="1" d="M472 85 L532 85" />
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-width="1" d="M592 85 L532 85" />
</g>
<g stroke-linecap="butt" >
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-dasharray="8,8" stroke-width="1" d="M388 141 L388 214" />
<path stroke="rgb(0,0,0)" fill="none" stroke-opacity="1.0" stroke-width="1" d="M388 287 L388 214" />
<path stroke-dasharray="none" d="M394.0 141.0 L388.0 153.0 L382.0 141.0" fill="none" stroke-width="1" stroke-opacity="1.0" stroke="rgb(0,0,0)" />
<path stroke-dasharray="none" d="M382.0 287.0 L388.0 275.0 L394.0 287.0" fill="none" stroke-width="1" stroke-opacity="1.0" stroke="rgb(0,0,0)" />
</g>
<g fill="rgb(164,225,255)" stroke="rgb(0,0,255)" fill-opacity="1.0" stroke-opacity="1.0" clip-path="url(#clipPath1_0_)" transform="translate(578,285)" >
<rect x="0" y="0" width="169" height="109" rx="20" ry="20" />
<text id="Metadata" x="62" y="14" fill="rgb(0,0,255)" font-weight="bold" fill-opacity="1.0" font-size="10" stroke="none">
Metadata
</text>
<text x="16" y="32" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="32" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
title
</text>
<text x="16" y="46" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="46" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
artist
</text>
<text x="16" y="60" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="60" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
cover
</text>
<text x="16" y="74" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="74" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
duration
</text>
</g>
<g fill="rgb(164,225,255)" stroke="rgb(0,0,255)" fill-opacity="1.0" stroke-opacity="1.0" clip-path="url(#clipPath4_0_)" transform="translate(592,29)" >
<rect x="0" y="0" width="169" height="109" rx="20" ry="20" />
<text id="Preferences" x="55" y="14" fill="rgb(0,0,255)" font-weight="bold" fill-opacity="1.0" font-size="10" stroke="none">
Preferences
</text>
<text x="16" y="32" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="32" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
audio_quality
</text>
<text x="16" y="46" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="46" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
audio_format
</text>
<text x="16" y="60" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="60" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
os
</text>
<text x="16" y="74" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="74" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
should_ask_metadata
</text>
</g>
<g fill="rgb(164,225,255)" stroke="rgb(0,0,255)" fill-opacity="1.0" stroke-opacity="1.0" clip-path="url(#clipPath3_0_)" transform="translate(42,289)" >
<rect x="0" y="0" width="169" height="109" rx="20" ry="20" />
<text id="Playlist" x="67" y="14" fill="rgb(0,0,255)" font-weight="bold" fill-opacity="1.0" font-size="10" stroke="none">
Playlist
</text>
<text x="16" y="32" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
*
</text>
<text x="2" y="32" fill="rgb(0,0,255)" fill-opacity="1.0" font-size="10" stroke="none">
P
</text>
<text x="26" y="32" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
playlist_id
</text>
<text x="16" y="46" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="46" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
number_elements
</text>
<text x="16" y="60" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="60" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
times_requested
</text>
</g>
<g fill="rgb(164,225,255)" stroke="rgb(0,0,255)" fill-opacity="1.0" stroke-opacity="1.0" clip-path="url(#clipPath6_0_)" transform="translate(302,31)" >
<rect x="0" y="0" width="169" height="109" rx="20" ry="20" />
<text id="User" x="73" y="14" fill="rgb(0,0,255)" font-weight="bold" fill-opacity="1.0" font-size="10" stroke="none">
User
</text>
<text x="16" y="32" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
*
</text>
<text x="2" y="32" fill="rgb(0,0,255)" fill-opacity="1.0" font-size="10" stroke="none">
P
</text>
<text x="26" y="32" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
user_id
</text>
<text x="16" y="46" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="46" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
username
</text>
<text x="16" y="60" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="60" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
name
</text>
</g>
<g fill="rgb(164,225,255)" stroke="rgb(0,0,255)" fill-opacity="1.0" stroke-opacity="1.0" clip-path="url(#clipPath2_0_)" transform="translate(305,287)" >
<rect x="0" y="0" width="169" height="109" rx="20" ry="20" />
<text id="Music" x="70" y="14" fill="rgb(0,0,255)" font-weight="bold" fill-opacity="1.0" font-size="10" stroke="none">
Music
</text>
<text x="16" y="32" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
*
</text>
<text x="2" y="32" fill="rgb(0,0,255)" fill-opacity="1.0" font-size="10" stroke="none">
P
</text>
<text x="26" y="32" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
file_id
</text>
<text x="16" y="46" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>
<text x="26" y="46" fill="rgb(0,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
video_id
</text>
<text x="16" y="60" fill="rgb(255,0,0)" fill-opacity="1.0" font-size="10" stroke="none">
o
</text>