ΑΒΡΑΞΑΣ

 ΑΒΡΑΞΑΣ

http://web.joang.com:8000/meta/

Ontology 기반 파일 관리 시스템
파일을 폴더로 관리하는 것이 아니라 메타 값을 가지고 분류하는 시스템
메타값은 온톨로지로 연결되어 각각의 메타값은 연계성을 갖는다.
첨부 파일은 업로드하는 파일 이외에도 Youtube를 공유 link로 저장하면 배치를 통하여 유투브 콘텐츠를 다운 받으며 유투브 내용을 본문에 파일명을 제목으로 생성한다.

Ontology 란

온톨로지.jpg온톨로지.jpg

ΑΒΡΑΞΑΣ 소개

라즈베리파이란 

20241211_181031.jpg

파일을 많이 관리하고 참조해야 하는 개인 직업 상의 이유로 파일을 폴더나 파일명으로 관리할 수 없고 파일에 폼함된 콘텐츠를 기준으로 파일을 관리하기 위하여 작성되넜다. 
 더불어 동영상을 폴더가 아니라 테마를 가지고 관리하고 웹상에서 실행하는 환경을 만들어 일정한 테마로 다수의 동영상을 순차적으로 실행하고 핸드폰으로도 출퇴근 시간에 감상할 수 있는 시스템이 필요 

  1. 자료 관리용으로 사용하는 경우 : http://www.joang.com --> http://web.joang.com:8000/meta
  2. 동영상 플레이어로 사용하는 경우 : http://web.joang.com:8082/archiver/login.do

1. 관리하는 문서의 이름과 원래 목적이 아니라 참고해야 하는 내용을 기준으로 다수의 메타를 정의하고 각각의 메타에 대한 관계성(ontology)를 수립하여 추적하여 검색할 수 있는 자료 관리 시스템을 만든다. 

2. 동영상을 저장할 때 소장하는 동영상 뿐만 아니라 유투브의 공유 기능을 이용하여 공유 URL만 입력하면 파일을 배치로 받아서 첨부하는 기능을 추가 --> 파일을 재생하고 감상하는 시스템을 만든다. 

ΑΒΡΑΞΑΣ 설치

[설치] 데이터베이스 설치(PostgreSql)

데이터베이스 설치(PostgreSql)

- PostgreSql 설치

- PostgreSql 외부 접근 허용

- 계정만들기

sudo -u postgres psql -c "ALTER ROLE postgres WITH password '여기패스워드'" postgres 계정으로 로그인 패스워드는 '여기패스워드'로 정한 패스워드

- adminer-4.8.1.php 설치

- Database 생성 

- 사용자 계정 생성 

- Table 생성 

[설치] Web Application Server 설치 (Tomcat)

- Java 설치

- Tomcat

- 자동실행 등록

[UNIT]
Description=apache-tomcat-9.0.64
After=syslog.target network.target

[Service]
Type=forking

Environment="CATALINA_HOME=/app/apache-tomcat-9.0.64"
Environment="CATALINA_BASE=/app/apache-tomcat-9.0.64"
Environment="CATALINA_OPTS=-Xms2048M -Xmx2048M -server -XX:+UseParallelGC"

ExecStart=/app/apache-tomcat-9.0.64/bin/startup.sh
ExecStop=/app/apache-tomcat-9.0.64/bin/shutdown.sh

User=pi
Group=pi
UMask=0000
RestartSec=10

[Install]
WantedBy=multi-user.target

재시작

[설치] Application 설치

 Application 설치

http://web.joang.com:8082/archiver.war 를 받아서 app/apache-tomcat-9.0.64/webapps에 war 파일 복사 

재시작을 하지 않아도 되지만 재시작 필요 시에 sudo systemctl restart tomcat.service 명령어 수행

[설치] 배치 구성하기 (Youtube, 백업)

Download YouTube

/home/pi/pythonDownloadCrontab/KKYouTuBeDownloader.py 생성 

from postgresqlDatabase import Databases
import yt_dlp
import datetime
import os
import re
import argparse, logging, logging.config, conf

today = datetime.date.today()
y = today.year
m = today.month
d = today.day
stored_file_name = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
base_dir = ""
dir = "/{year}/{month}/{day}/".format(year=y,month=m,day=d)
downloadfilename = ""
metadata = ""

# Log
logging.config.dictConfig(conf.dictConfig)
logger = logging.getLogger(__name__)

class CRUD(Databases):
    def insertDB(self,schema,table,colum,data):
        sql = " INSERT INTO {schema}.{table}({colum}) VALUES ('{data}') ;".format(schema=schema,table=table,colum=colum,data=data)
        try:
            self.cursor.execute(sql)
        except Exception as e :
            logger.debug(" insert DB err, e="+str(e)) 
    
    def readDB(self,table,colum, condition):
        sql = " SELECT {colum} from {table} where 1=1 {condition}".format(colum=colum,table=table, condition=condition)
        try:
            self.cursor.execute(sql)
            result = self.cursor.fetchall()
        except Exception as e :
            result = (" read DB err",str(e))
        
        return result
    
    def readDBbySQL(self,sql):
        try:
            self.cursor.execute(sql)
            result = self.cursor.fetchall()
        except Exception as e :
            result = (" read DB err",str(e))
        
        return result

    def updateDB(self,table,colum,value,condition):
        sql = " UPDATE {table} SET {colum}='{value}' WHERE 1=1 and {condition}::integer ".format(table=table , colum=colum ,value=value,condition=condition )
        try :
            self.cursor.execute(sql)
        except Exception as e :
            logger.debug(" update DB err , e="+str(e))

    def deleteDB(self,schema,table,condition):
        sql = " delete from {schema}.{table} where {condition} ; ".format(schema=schema,table=table,
        condition=condition)
        try :
            self.cursor.execute(sql)
        except Exception as e:
            logger.debug( "delete DB err , e="+str(e))
            
    def commit(self):
        try :
            self.db.commit()
        except Exception as e:
            logger.debug( "delete DB err , e="+str(e))
            
    def downLoadMovieFileByURL(self,downloadurl, idx, file_title):
        global downloadfilename
        logger.debug( ">> Download Movie URL:" + downloadurl)
        ydl_opts = {
             'verbose': True,  
             'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo+bestaudio/best',
             'merge_output_format': 'mp4',
             'outtmpl': base_dir + dir + stored_file_name + file_title + '.%(ext)s'
        }
        try:
            yt_dlp.YoutubeDL(ydl_opts).cache.remove()
            ydl = yt_dlp.YoutubeDL(ydl_opts).extract_info(downloadurl, download=True)
            downloadfilename = ydl["title"] 
            metadata = ydl['description']
            logger.debug(">> Movie file name : " + downloadfilename)
            logger.debug(">> Movie metadata : " + metadata )
            db.updateDB('tb_filemanager_meta_file', 'file_detail', downloadurl+"\n\r"+ metadata.replace("'","\""), 'idx='+idx)
            return True
        except Exception as e:
            logger.debug("Error e="+str(e))
            db.updateDB('tb_filemanager_meta_file', 'down_yn', 'E', 'idx='+idx)
            db.updateDB('tb_filemanager_meta_file', 'error', '@downLoadMovieFileByURL:'+str(e), 'idx='+idx)
            return False
        
    def downLoadMusicFileByURL(self,downloadurl, idx, file_title):
        global downloadfilename
        logger.debug( ">> Download Music URL:" + downloadurl)
        ydl_opts = {
             'verbose': True,  
             'format': 'bestaudio/best',
             'postprocessors': [{
                    'key': 'FFmpegExtractAudio',
                    'preferredcodec': 'mp3',
                    'preferredquality': '192',
              }, {'key': 'FFmpegMetadata'},],
             'outtmpl': base_dir + dir + stored_file_name + file_title + '.%(ext)s'
        }
        try:
            yt_dlp.YoutubeDL(ydl_opts).cache.remove()
            ydl = yt_dlp.YoutubeDL(ydl_opts).extract_info(downloadurl, download=True)
            downloadfilename = ydl["title"]
            metadata = ydl['description']
            logger.debug(">> Music file name : " + downloadfilename )
            logger.debug(">> Music metadata : " + metadata )
            db.updateDB('tb_filemanager_meta_file', 'file_detail', downloadurl+"\n\r"+ metadata.replace("'","\""), 'idx='+idx)
            return True
        except Exception as e:
            logger.debug("Error e=" + str(e))
            db.updateDB('tb_filemanager_meta_file', 'down_yn', 'E', 'idx='+idx)
            db.updateDB('tb_filemanager_meta_file', 'error', '@downLoadMusicFileByURL:'+str(e), 'idx='+idx)
            return False

    def updateAndRename(self, idx, downloadFileType):
        try:
            logger.debug("> Download Original file name = " + base_dir + dir + downloadfilename + ", type=" + downloadFileType)
            changeOrgFileName = re.sub("'", "", re.sub("[/]", "_", re.sub('[\/:*?"<>|]','',downloadfilename)))
            logger.debug("> Change Original file name = " + base_dir + dir + changeOrgFileName + ", type=" + downloadFileType)
            logger.debug("> Change Store file name = " + base_dir + dir + stored_file_name + ", type=" + downloadFileType)
      
            if(downloadFileType == "mov"):
                final_changeOrgFileName = changeOrgFileName+'.mp4' 
                final_stored_file_name = stored_file_name+'.mp4'
            elif(downloadFileType == "muc"):
                final_changeOrgFileName = changeOrgFileName+'.mp3'
                final_stored_file_name = stored_file_name+'.mp3'

            for filename in os.listdir(base_dir + dir):
                logger.debug(">> filename = " + filename + " , stored_file_name=" + stored_file_name)
                if filename.startswith(stored_file_name):
                    logger.debug("> Change file name ("+idx+")= " + base_dir + dir + filename + " to " + base_dir + dir + final_stored_file_name)
                    os.rename(base_dir + dir + filename, base_dir+dir + final_stored_file_name)
                    logger.debug("> Changed file stored name=" + final_stored_file_name)
                    logger.debug("> Changed file Org name=" + final_changeOrgFileName)
                    
            logger.debug("original_file_name ("+idx+")= " + final_changeOrgFileName)
            db.updateDB('tb_filemanager_meta_file', 'original_file_name', final_changeOrgFileName, 'idx='+idx)
            logger.debug("stored_file_name ("+idx+")= " + dir + final_stored_file_name)
            db.updateDB('tb_filemanager_meta_file', 'stored_file_name', dir + final_stored_file_name, 'idx='+idx)
            logger.debug("file_size ("+idx+")= " + base_dir + dir + final_stored_file_name)
            logger.debug("file_size ("+idx+")= " + str(os.path.getsize(base_dir + dir + final_stored_file_name)))
            db.updateDB('tb_filemanager_meta_file', 'file_size', os.path.getsize(base_dir + dir + final_stored_file_name), 'idx='+idx)
            logger.debug("crea_dtm ("+idx+") = NOW()")
            db.updateDB('tb_filemanager_meta_file', 'crea_dtm', 'NOW()', 'idx='+idx)
            logger.debug("crea_dtm ("+idx+") = NOW()")
            return True
        except Exception as e:
            logger.debug("Error e=" + str(e))
            db.updateDB('tb_filemanager_meta_file', 'down_yn', 'E', 'idx='+idx)
            db.updateDB('tb_filemanager_meta_file', 'error', '@updateAndRename:'+str(e), 'idx='+idx)
            return False
        
        
        
    def existDirectory(self,directory):
        logger.debug(">>" + directory)
        isDir = os.path.isdir(directory)
        if(isDir):
            logger.debug(">>> Exist !")
        else:
            logger.debug(">>> Make Dir !")
            os.makedirs(directory, exist_ok=True)
        return isDir



if __name__ == "__main__":
    db = CRUD()
    result = db.readDB('tb_archiver_sys_info','sys_storage', 'and sys_title=\'ΑΒΡΑΞΑΣ\'')
    if( len(result) == 0 ):
        logger.debug(">> sys_storage result size 0 " )
    else:
        logger.debug(">> sys_storage result size " + str(len(result)) )
        base_dir = result[0][0]
        logger.debug(">> base_dir = " + base_dir)
    
    result = db.readDB('tb_filemanager_meta_file','idx, original_file_name, file_type, file_title', 'and down_yn=\'N\'')
    resultYN = 'N'
    
    if( len(result) == 0 ):
        logger.debug(">> result size 0 " )
    else:
        logger.debug(">> result size " + str(len(result)) )
        row=result[0]
        logger.debug(">> Row detail " + str(row) )
        db.existDirectory(base_dir+dir)
        idx = str(row[0])
        downloadUrl = row[1]
        downloadFileType = row[2]
        file_title = row[3]
        db.updateDB('tb_filemanager_meta_file', 'down_yn', 'D', 'idx='+idx)
        db.commit()
        logger.debug(">>"+idx+" , "+downloadUrl+" , "+downloadFileType)
        if(downloadFileType == "mov"):
            logger.debug("> MOVIE !")
            if(db.downLoadMovieFileByURL(downloadUrl, idx, file_title)):
                if(db.updateAndRename(idx, downloadFileType)):
                    resultYN = 'Y'
                else:
                    resultYN = 'E'
            else:
                resultYN = 'E'
        elif(downloadFileType == "muc"):
            logger.debug("> MUSIC !")
            if(db.downLoadMusicFileByURL(downloadUrl, idx, file_title)):
                if(db.updateAndRename(idx, downloadFileType)):
                    resultYN = 'Y'
                else:
                    resultYN = 'E'
            else:
                resultYN = 'E'
        else:
            logger.debug("> ERROR FILE TYPE !")
            db.updateDB('tb_filemanager_meta_file', 'down_yn', 'E', 'idx='+idx)
            db.updateDB('tb_filemanager_meta_file', 'error', '@DownloadType', 'idx='+idx)
        db.updateDB('tb_filemanager_meta_file', 'down_yn', resultYN, 'idx='+idx)
        if(resultYN == ""):
            db.updateDB('tb_filemanager_meta_file', 'error', 'download done', 'idx='+idx)
        logger.debug(">> "+idx+" UPDATE=" + resultYN)
    db.commit()

Backup :실제 파일이름으로 변환해서 백업 

/home/pi/pythonDownloadCrontab/KKBackupFiles.py 파일을 생성 

from postgresqlDatabase import Databases
import yt_dlp
import datetime
import os
import re
import argparse, logging, logging.config, conf
from shutil import copyfile

today = datetime.date.today()
y = today.year
m = today.month
d = today.day
stored_file_name = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
dir = "/{year}/{month}/{day}/".format(year=y,month=m,day=d)

# Log
logging.config.dictConfig(conf.dictConfig)
logger = logging.getLogger(__name__)

class CRUD(Databases):
   
    def readDB(self,table,colum, condition):
        sql = " SELECT {colum} from {table} where 1=1 {condition}".format(colum=colum,table=table, condition=condition)
        try:
            self.cursor.execute(sql)
            result = self.cursor.fetchall()
        except Exception as e :
            result = (" read DB err",str(e))
        
        return result
 
    def updateDB(self,table,colum,value,condition):
        sql = " UPDATE {table} SET {colum}='{value}', sys_backup_date=NOW() WHERE 1=1 and {condition} ".format(table=table , colum=colum ,value=value,condition=condition )
        try :
            self.cursor.execute(sql)
        except Exception as e :
            logger.debug(" update DB err , e="+str(e))

    def backupFile(self,sys_storage, sys_backup_location):
       sql = " SELECT original_file_name, stored_file_name from tb_filemanager_meta_file order by idx  "
       try:
        self.cursor.execute(sql)
        result = self.cursor.fetchall()
       except Exception as e :
        result = (" read DB err",str(e)) 
       for row in result:
        toLocation = row[1].rindex("/", 0)
        #logger.debug(">> row = " + row[1][:toLocation+1] + " = " + str(toLocation))
        #logger.debug(">> row = " + sys_storage + row[1] + " --> TO --> " + sys_backup_location + "/" + row[1][:toLocation]  + row[0])
        self.copyBackupFile(sys_storage + row[1], sys_backup_location + row[1][:toLocation] , row[0])
        
    def copyBackupFile(self, orgFile, destDir, destFile):
        if not os.path.exists(destDir + "/" + destFile):
            logger.debug(">> file not exist = " + destFile)
            # 디렉토리 만들기 
            if not os.path.exists(destDir):
                logger.debug(">> Make Dir = " + destDir)
                os.makedirs(destDir)
            # 파일 옮기기 
            logger.debug(">> Copy Files = " + orgFile + " --> " + destDir + "/" + destFile )
            os.system('cp ' + orgFile + ' "' + destDir + "/" + destFile + '"') 
            
        else:
            logger.debug(">> file exist ! -> " + destDir + "/" + destFile)
            


if __name__ == "__main__":
    db = CRUD()
    result = db.readDB('tb_archiver_sys_info','SYS_BACKUP_YN, sys_storage, sys_backup_location', 'and SYS_TITLE=\'ΑΒΡΑΞΑΣ\' and SYS_BACKUP_YN=\'Y\'')
    
    if( len(result) == 0 ):
        logger.debug(">> Backup Skip " )
    else:
        logger.debug(">> result size " + str(len(result)) )
        row=result[0]
        logger.debug(">> Row detail " + str(row) )
        if( str(row[0]) == "Y" ):
            logger.debug(">> BACKUP START  ! ")
            db.updateDB('tb_archiver_sys_info', 'SYS_BACKUP_YN', 'P', 'SYS_TITLE=\'ΑΒΡΑΞΑΣ\'')
            db.commit()
            sys_storage = str(row[1])
            sys_backup_location = str(row[2])
            db.backupFile(sys_storage, sys_backup_location)
        db.updateDB('tb_archiver_sys_info', 'SYS_BACKUP_YN', 'N', 'SYS_TITLE=\'ΑΒΡΑΞΑΣ\'')
    db.commit()

Python 공통 

/home/pi/pythonDownloadCrontab/conf.py 생성 


from pathlib import Path

p = Path("logs")
if not p.exists():
    p.mkdir()

dictConfig = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': '%(asctime)s [%(levelname)s] %(name)s:: %(message)s',
        },
    },
    'handlers': {
        'default': {
            'level': 'DEBUG',
            'formatter': 'standard',
            'class': 'logging.StreamHandler',
            'stream': 'ext://sys.stdout',
        },
        'file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'DEBUG',
            'formatter': 'standard',
            'filename': 'logs/logfile.log',
            'mode': 'a',
            'maxBytes': 5_242_880,
            'backupCount': 3,
            'encoding': 'utf-8',
        },
    },
    'loggers': {
        '__main__': {
            'handlers': ['default','file'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'camera': {
            'handlers': ['default', 'file'],
            'level': 'DEBUG',
            'propagate': False,
        },
    }
}

/home/pi/pythonDownloadCrontab/postgresqlDatabase.py   생성 

import psycopg2

class Databases():
    def __init__(self):
        self.db = psycopg2.connect(host='localhost', dbname='archiver',user='pi',password='archiverpw123!@#',port=5432)
        self.cursor = self.db.cursor()

    def __del__(self):
        self.db.close()
        self.cursor.close()

    def execute(self,query,args={}):
        self.cursor.execute(query,args)
        row = self.cursor.fetchall()
        return row

    def commit(self):
        self.db.commit()
    

Crontab 설정 

*/10 * * * * /usr/bin/python /home/pi/pythonDownloadCrontab/KKYouTuBeDownloader.py > /home/pi/logs/sysout.log
*/13 * * * * /usr/bin/python /home/pi/pythonDownloadCrontab/KKBackupFiles.py > /home/pi/logs/backup.log

10 분마다 Youtube 다운로드 찾아 다운로드 실행 

13분마다 백업 여부를 확인하고 백업이 있을 때 배치로 수행 

실행 

  1. http://localhost:8080/archiver/login.do

ΑΒΡΑΞΑΣ 사용하기

  1. 처음 사용하기

    • 로그인 
    • ΑΒΡΑΞΑΣ 아브락 삭스 
    • 아브라삭스 1.0 By Hyeonsu Ryu , build version : 59   
    • 메타검색 / 파일 겁색 / 온톨로지 보기 / 로그아웃 / 사용자정보 / 관리자(관리자 권한만 보임) 
  2. 사용자 정보

    • 이름 바꾸기
    • 패스워드 변경  : 관리자 초기 로그인 후 패스워드 변경 필수 
    • 메시지 
    • 메인 이미지 변경 : 이미지 개인화 . 이미지 url을 입력할 수 있다. 개인 사진 등 ... 
  3. 온톨로지

  4. 파일 올리기 (글쓰기)

    • 파일 올리고 글쓰기 
    • YouTube 동영상 등록하기 
    • 메타 정의하기 
  5. 메타 조회하기

  6. 메타Merge

  7. 파일 조회하기

  8. 복합조건 조회하기

  9. Play video

  10. 파일 공유하기

  11. 관리자 기능

    • 기준정보 변경 
    • 저장위치 변경 
    • 백업
    • 등록 사용자 확인 


버전 업그레이드 정보

버전 09 --> 1.0 

: ALTER TABLE tb_users ADD COLUMN logindate date NOT NULL;   실행 후 업그레이드