Danh sách phát video với thời gian bắt đầu và kết thúc


10

Có một ứng dụng GUI tốt (ví dụ: GUI mplayer hoặc một cái gì đó như banshee) cho linux cho phép tạo và chỉnh sửa danh sách phát (cho các tệp video) với thời gian bắt đầu và dừng khác nhau cho mỗi video trong danh sách?

Đã thêm :

Hiện tại tôi tạo các tệp thủ công có chứa một cái gì đó như thế:

video.avi -ss 2440 -endpos 210
#some comment

video2.mp4 -ss 112 -endpos 2112

Sau đó, tôi có một kịch bản bao bọc cho: mplayer -fs $(grep -v "^ #" $1)

Hơn nữa, tôi đã viết một số hàm emacs để đơn giản hóa việc chỉnh sửa các tệp như vậy một chút. (Giống như chuyển đổi thời gian bắt đầu và kết thúc từ định dạng hh: mm: ss sang giây và thời gian kết thúc sang vị trí tương đối (thời gian kết thúc - thời gian bắt đầu) theo yêu cầu của -endpose (Tôi có thể đăng các macro nếu ai đó quan tâm). Tuy nhiên, điều đó vẫn quá khó chịu. Vì vậy, câu hỏi của tôi là nếu có một GUI đẹp để thực hiện điều này (ví dụ: cho phép bạn đánh dấu trong dòng thời gian video thời gian bắt đầu và kết thúc cho danh sách phát, v.v.).


@ user5289: Nếu bạn chỉ quan tâm đến câu trả lời cho Ubuntu (bạn không đề cập đến phân phối trong câu hỏi của mình), bạn có thể chọn trang web nào để hỏi. Nếu bạn thích Hỏi Ubuntu, hãy sử dụng flagnút trên câu hỏi của bạn và yêu cầu nó được di chuyển.
Gilles 'SO- ngừng trở thành ác quỷ'

1
@ user5289 Có phải tất cả những gì bạn muốn .. để có thể phát video trong GUI (vì 'mplayer' chắc chắn không phải là GUI)? ... Hoặc bạn có muốn đặt các vị trí thời gian trong GUI (cũng) không? .. bởi vì bạn chỉ có thể sử dụng Smplayer để sử dụng "lệnh thời gian" hiện có của mình .. Tôi đã viết một kịch bản để làm việc đó .. Tôi sẽ đăng kịch bản như và trả lời .. ai đó có thể thấy nó xen vào .. Tôi chắc chắn thấy phương pháp của bạn thú vị .. và tôi vừa điều chỉnh nó thành Smplayer ..
Peter.O

@ fred.bear, vâng, vấn đề là tôi muốn có thể đặt các vị trí thời gian trong GUI, chỉnh sửa toàn bộ danh sách phát trong GUI theo cách thoải mái. (Chơi trong GUI không quan trọng)
sinh viên

@ user5289: Hoàn toàn có thể đặt các vị trí thời gian trong GUI ... Tôi thực hiện điều đó với Smplayer .... Tôi đã thêm timestampstập lệnh mới vào câu trả lời ban đầu chỉ hiển thị play-it-in-Smplayertập lệnh
Peter.O

Câu trả lời:


3

Có lẽ tôi đang nhận được câu hỏi sai, vì tiếng Anh không phải là ngôn ngữ đầu tiên của tôi, nhưng sẽ tốt hơn nếu bạn chỉnh sửa video bằng một công cụ như Kino thay vì tạo danh sách phát như vậy?

Bạn có thể điều chỉnh thời gian bắt đầu và dừng theo ý muốn và tôi không nghĩ nó sẽ khó đến thế.


2
Vâng, tôi biết cách cắt video bằng Kino hoặc những thứ tương tự. Câu hỏi thực sự là về danh sách phát, không phải về việc tạo video mới. Tạo danh sách phát như vậy sẽ rất nhanh, linh hoạt và không tốn dung lượng đĩa.
sinh viên

3

CẬP NHẬT-2: Sau khi gửi tập lệnh sau, tôi nhận ra rằng một cách khác để thiết lập các vị trí thời gian (trong GUI) là sử dụng Trình chỉnh sửa phụ đề (ví dụ gnome-subtitles:). Bạn chỉ có thể nhấp để đánh dấu vị trí bắt đầu và kết thúc của "phụ đề ảo"; thực tế bạn có thể đặt đường dẫn tệp và nhận xét của mình thành "phụ đề" ... Một số định dạng không phù hợp (ví dụ: sử dụng số khung) .. 'Tệp phụ đề ViPlay', Power DivX và 'Adobe Encore DVD' tốt

CẬP NHẬT-1; một tập lệnh mới ... Tập lệnh này sẽ không cung cấp cho bạn khả năng danh sách phát tích hợp, nhưng nó sẽ cho phép bạn chọn và lưu và sửa đổi thời gian bắt đầu và kết thúc trong Smplayer mà không cần phải nhập bất cứ điều gì.

Thông tin này được lưu trong một tệp cấu hình, các đường dẫn tệp có thể được "phát" riêng lẻ hoặc được nhóm theo một chuỗi, thông qua một tập lệnh khác (tương tự như tập lệnh 'play' của tôi hoặc như tập lệnh Emacs của bạn) ..

Nó hoạt động bằng cách sử dụng Seekhộp thoại của Smplayer ... xmacrothao tác hộp thoại (Tôi thấy rằng nó cần sleep .3giữa các lệnh xmacro) ... Thời gian được lưu trữ ở định dạng HH: MM: SS trong một tệp trong ~/.config/smplayer... Dòng thứ nhất là Thời gian bắt đầu, dòng thứ 2 là Thời gian kết thúc và dòng thứ 3 ở đó để chỉ định thư mục gốc ... Dòng thứ 3 này được sử dụng làm chỉ báo đường dẫn tùy chọn bởi tập lệnh folow-up để sửa đổi cài đặt cấu hình smplayer bằng mồi nó với -ss-endpos... Tệp cấu hình dấu thời gian được đặt tên giống như tệp phương tiện, với .smplayhậu tố ...

Vì vậy, đây không phải là tất cả những gì bạn muốn, nhưng nó có thể giúp thiết lập thời gian mà không cần gõ ...

Đây là kịch bản 'lấy dấu thời gian':

#!/bin/bash
# Bind this script to a key-combination of your choice..
# It currently responds only to an Smplayer window.  

id=$(xdotool getactivewindow)
title="$(xwininfo -id "$id" |
  sed -n "2s/^xwininfo: Window id: \(0x[[:xdigit:]]\+\) \x22\(.*\)\x22$/\2/p")"

if [[ $title =~ ^.*\ -\ SMPlayer$ ]] ; then
  smplayer_d="$HOME/.config/smplayer"
  clip_d="$smplayer_d/clips"
  [[ ! -d "$clip_d" ]] && mkdir -p "$clip_d"
  bname="${title% - SMPlayer}"
  clip_f="$clip_d/$bname.smplay" # Same name as video, with '.smplay' suffix

  if [[ ! -f "$clip_f" \
      || "$(<"$clip_f" wc -l)" != "3" ]]
  then     # Prime with three defaults
           # FROM     TO      ROOT-dir
    echo -e "0:00:00\n0:00:00\n"     >"$clip_f"
  fi

  # Get timestamp, in seconds, of current stream position (from the current window)
  #   using the "Smplayer - seek" dialog, via  Ctrl+j
  sleep .3; echo -n "KeyStrPress Control_L  KeyStrPress j       KeyStrRelease j       KeyStrRelease Control_L" | xmacroplay -d 10 :0.0 &>/dev/null 
  sleep .3; echo -n "                       KeyStrPress Home    KeyStrRelease Home                           " | xmacroplay -d 10 :0.0 &>/dev/null 
  sleep .3; echo -n "KeyStrPress Shift_L    KeyStrPress End     KeyStrRelease End     KeyStrRelease Shift_L  " | xmacroplay -d 10 :0.0 &>/dev/null 
  sleep .3; echo -n "KeyStrPress Control_L  KeyStrPress c       KeyStrRelease c       KeyStrRelease Control_L" | xmacroplay -d 10 :0.0 &>/dev/null
  sleep .3; echo -n "                       KeyStrPress Escape  KeyStrRelease Escape                         " | xmacroplay -d 10 :0.0 &>/dev/null 
    seekHMS="$(xsel -o -b)"
  # Now set config times to defaults (in case of malformed times)
      ssHMS="0:00:00"
  endposHMS="0:00:00"
  # Now get config data from config file
  eval "$( sed -ne "1s/^\([0-9]\+\):\([0-5][0-9]\):\([0-5][0-9]\)$/    ssHMS=\"&\"/p" \
                -e "2s/^\([0-9]\+\):\([0-5][0-9]\):\([0-5][0-9]\)$/endposHMS=\"&\"/p" \
                -e "3s/.*/   root_d=\"&\"/p" "$clip_f" )"

  # Present dialog to set specifick  items.
  REPLY=$(zenity \
   --list --height=310 --width=375 \
   --title="Set Clip Start / End Time" \
   --text=" Select Clip Start / End  for time:  $seekHMS\n\
       or choose another option\n\
       \tthen click OK" \
   --column="Position" --column=" " --column="Current Setting  "  \
            "Clip Start"        " "          "$ssHMS" \
            "Clip End"          " "          "$endposHMS" \
            "UNSET Start"       " "          " " \
            "UNSET End"         " "          " " \
            "* Open directory"  " of"        "config files *" 
  ); 
  [[ "$REPLY" == "Clip Start"       ]] && sed -i -e "1 s/.*/$seekHMS/" "$clip_f"
  [[ "$REPLY" == "Clip End"         ]] && sed -i -e "2 s/.*/$seekHMS/" "$clip_f"
  [[ "$REPLY" == "UNSET Start"      ]] && sed -i -e "1 s/.*/0:00:00/"  "$clip_f"
  [[ "$REPLY" == "UNSET End"        ]] && sed -i -e "2 s/.*/0:00:00/"  "$clip_f"
  [[ "$REPLY" == "* Open directory" ]] && nautilus "$clip_d"
fi  

Kịch bản sau đây là bản gốc 'play "ban đầu của tôi. Nó độc lập với kịch bản Timestamp sẵn có, nhưng sẽ không mất nhiều thời gian để chúng hoạt động cùng nhau ...

Nó sẽ 'lái' Smplayer, sử dụng mplayer bên trong .. ít nhất, đó là một GUI bình thường, nhưng danh sách phát của bạn sẽ cần phải có trong trình soạn thảo văn bản của bạn .. và bạn rõ ràng đã biết về phương pháp đó rồi :)

Tôi đã thử điều này một vài năm trước đây, nhưng tôi đã quên tất cả về nó vì tôi thường không cần một thứ như vậy, nhưng thật tốt khi giữ "dấu trang" .. Tôi rất vui vì bạn đã hồi sinh ý tưởng. Đây là kịch bản ... mà thực sự chỉ làm giống như bạn đã làm, nhưng với Smplayer (một người chơi trò chơi GUi)

#
# Summary: 
#   Play one video (only) in 'smplayer', passing -ss and -endpos values to 'mplayer'
#   It uses 'locate' to get the path of the video (by just its basename)
#
# eg:
#     $1                              $2   $3       $4 
#     basename                       -ss  -endpos   root 
#     "Titus - The Gorilla King.mp4"  240  30      "$HOME"  # A fascinating documentary of the long reign of a silver-back gorialla
#

[[ "$2" == "" ]] && set "$1"  0   "$3"   "$4"
[[ "$3" == "" ]] && set "$1" "$2"  36000 "$4"  # 36000 is arbitary (24 hours) 
[[ "$4" == "" ]] && root="$HOME" || root="$4"

file=( "$(locate -er "^$root/\(.*/\)*\+$1$")" )

# 1) Tweak 'smplayer.ini' to run 'mplayer' with the specified -ss and -endpos  times
# 2) Run 'smplayer' to play one video only. The time settings will hold afer exit,  
#                         so the script waits (backgrounded) for smplayer to exit
# 3) When 'smplayer' exits, set values to extreme limits:  -ss 0 -endpos 3600 
#                           or(?): TODO remove the settings enitrely, 
#                                       but that requires a different regex
a=0 z=36000     
# 
# -ss <time> (also see -sb)
# -ss 56       # Seeks to 56 seconds.
# -ss 01:10:00 #Seeks to 1 hour 10 min.
#
# -endpos <[[hh:]mm:]ss[.ms]|size[b|kb|mb]> (also see -ss and -sb)
#         Stop at given time or byte position.
#         NOTE: Byte position is enabled only for MEncoder and will not be accurate, as it can only stop at a frame boundary.  
#         When used in conjunction  with -ss option, -endpos time will shift forward by seconds specified with -ss.
#        -endpos 56        # Stop at 56 seconds.
#        -endpos 01:10:00  # Stop at 1 hour 10 minutes.
# -ss 10 -endpos 56        # Stop at 1 minute 6 seconds.
#        -endpos 100mb     # Encode only 100 MB.
#
#                                                        -ss       0                -endpos       36000                                     
#              \1                              \2      \3        \4        \5     \6            \7            \8                 
 sed -i -e "s/^\(mplayer_additional_options.*\)\( \|=\)\(-ss \+\)\([^ ]\+\)\( .*\)\(-endpos \+\)\([0-9:mb]\+\)\(.*\)/\1\2\3${2}\5\6${3}\8/"  $HOME/.config/smplayer/smplayer.ini
(smplayer "$file" 
 sed -i -e "s/^\(mplayer_additional_options.*\)\( \|=\)\(-ss \+\)\([^ ]\+\)\( .*\)\(-endpos \+\)\([0-9:mb]\+\)\(.*\)/\1\2\3${a}\5\6${z}\8/"  $HOME/.config/smplayer/smplayer.ini
)
exit

Cảm ơn các cập nhật. Bạn có thể thêm một hướng dẫn từng bước làm thế nào để sử dụng tập lệnh?
sinh viên

@ người dùng5289. Bạn chỉ nên yêu cầu bạn mở smplayer với video của mình và tập lệnh được liên kết với phím tắt (Tôi sử dụng xbindkeys, nhưng mọi thứ sẽ làm được) .. Tại bất kỳ thời điểm nào trong phim, bạn chỉ cần nhấn phím tắt -key .. Bởi vì nó sử dụng một macro không liên quan đến smplayer, bạn không nên làm bất cứ điều gì (nhấp chuột hoặc bàn phím) cho đến khi hộp thoại thứ 2 xuất hiện. Cần 1-2 giây để kiểm tra "Đây có phải là cửa sổ phù hợp không? V.v" và mở hộp thoại "tìm kiếm" của người chơi từ đó macro sao chép vị trí thời gian hiện tại được trình bày trong HH: MM: SS .. Không làm gián đoạn hộp thoại này. ...
Peter.O

tiếp tục ... Macro sẽ sao chép dấu thời gian vào clipoard và sau đó đóng "hộp thoại tìm kiếm" .. Một hộp thoại thứ hai sau đó sẽ xuất hiện (hộp thoại "zquil") ... Nó sẽ nhắc bạn thực hiện 1 trong 5 điều. 1) sử dụng dấu thời gian đã chụp làm vị trí Bắt đầu. 2) sử dụng dấu thời gian đã chụp làm vị trí Kết thúc. 3) Unset Bắt đầu Positon. 4) Bỏ đặt kết thúc Positon. 5) Mở nautilus tại thư mục chứa tệp "config" đã lưu .. Các tệp cấu hình được đặt tên giống hệt với Video. (tên được lấy từ thanh tiêu đề của Smplayer) ..
Peter.O

tiếp tục ... Từ đó bạn có thể sử dụng thời gian tùy ý trong các tập lệnh hiện tại của mình ... Tôi đang làm việc với một kịch bản tích hợp với Smplayer; Kịch bản smplayer đầu tiên của tôi (hiển thị trong câu trả lời ban đầu của tôi) hơi ngây thơ và vấp phải một số tùy chọn .. Smplayer có một tùy chọn để giữ lịch sử của mọi tệp từng được phát. Điều này có thể được thực hiện trong một tệp hoặc một tệp riêng lẻ ... Phương thức tệp riêng lẻ (mặc định, tôi nghĩ (?), Là phù hợp nhất, nhưng tên .ini được băm. Tôi hiện đang làm việc bắt chước thuật toán ... vì vậy hãy theo dõi :)
Peter.O

tiếp tục ... Bạn sẽ cần cài đặt các ứng dụng này .. xdotool xwininfo xmacro zenity sed(nhưng ai chưa có sed :), và tất nhiên smplayer... Như tôi đã đề cập, câu trả lời của tôi .. nó chỉ là một 'asssist' .. cho đến nay , nhưng nghĩ về nó ngay bây giờ, khi tôi viết bài này, nó có thể được thực hiện để ghép vào danh sách phát smplayer bình thường! bởi vì danh sách phát sẽ phát theo các tập tin lưu trữ Tôi vẫn phải hoàn thành thuật toán băm đó
Peter.O

2

Tôi đã thêm câu trả lời thứ hai này, vì nó hoạt động như một danh sách phát bình thường trong SMPlayer và ở đây tốt hơn cho sự rõ ràng ...

Tôi đã có nó hoạt động hoàn hảo thông qua danh sách phát ...

Phương pháp này yêu cầu biên dịch lại SMPlayer và phương thức đặt tên tệp cụ thể ... Chỉ có một chức năng trong nguồn SMPlayer's được sửa đổi và 3 tiêu đề được thêm vào cùng một tệp nguồn ... Tôi đã biên dịch smplayer_0.6.8cho Lucid .. Maveric và Meerkat sử dụng smplayer_0.6.9.. Một dòng trong phiên bản sau thì khác, nhưng điều đó không làm đảo lộn bất cứ điều gì ... Đây là chức năng và tiêu đề được sửa đổi chosmplayer_0.6.8

Tuy nhiên, hộp thoại tiện nghi trong câu trả lời trước của tôi vẫn được sử dụng để ghi lại thời gian bắt đầu và kết thúc ...

GHI NHỚ - Các phân đoạn nguồn sau đây dành cho smplayer_0.6.8... Tệp cần sửa đổi là: ../smplayer-0.6.9/src/findsubtitles/osparser.cpp... Các phân đoạn mới giống nhau cho '0.6.8' và '0.6.9', nhưng các bản gốc khác nhau theo một dòng (rất gần với kết thúc, ngay trước trận chung kết return hexhash;)


Thêm khối dòng đầu tiên này ngay bên dưới các #includetiêu đề hiện có

// ====================
// fred mod begin block  
#include <QFileInfo>
#include <QRegExp>
#include <QSettings>
#include "paths.h"
// fred mod end block
// ==================

Đây là chức năng sửa đổi

QString OSParser::calculateHash(QString filename) {
    QFile file(filename);

    if (!file.exists()) {
        qWarning("OSParser:calculateHash: error hashing file. File doesn't exist.");
        return QString();
    }

    file.open(QIODevice::ReadOnly);
    QDataStream in(&file);
    in.setByteOrder(QDataStream::LittleEndian);
    quint64 size=file.size ();
    quint64 hash=size; 
    quint64 a;
    for(int i = 0; i < 8192; i++) {
        in >> a ; hash += a;
    };
    file.seek(size-65536);
    for(int i = 0; i < 8192; i++) {
        in >> a ; hash += a;
    };

  // =====================================================================
  // fred mod begin block
  //  
  // A mod to enable unique smplayer .ini files to be created for  
  //        content-identical media files whose file-names match
  //        a specific pattern based on two timestamps. 
  //        This is the naming pattern:

  //          
  //           name.[00:11:22].[33.44.55].mkv
  //              
  //        The two time stamps indicate the start and end  points of a 
  //         clip to be played according to  settings in the unique .ini
  //            
  //        The so named files can be, and typically will be, soft (or hard) links.   
  //        The "original" file can also named in this manner, if you like,    
  //        but that would make the "original" start playing as a clip,
  //          NOTE: soft links become invalid when you rename the original file.  
  //
  //  Note: For this system to work, you need to enable the following:
  //        In SMPlayer's GUI, open the Options dialog...
  //        In the  "General" tab... "Media settings"... 
  //          enable: 〼 "Remember settings for all files (audio track, subtitles...)" 
  //                     "Remember time position"   can be 'on' or 'off'; it is optional1
  //                                                but it is disabled for these clips.    
  //                     "Store setings in" must be: "multiple ini files" 
  //
  QFileInfo fi(filename);
  QString name = fi.fileName();
  //
  // ===================================================================
  // This RegExp expects a name-part, 
  //             followed by 2 .[timestamps]  (Begin-time and End-time)
  //             followed by a .extension
  //              
  //              .[ Begin  ].[  End   ]  
  //      eg. name.[00:11:22].[33.44.55].mkv
  //
  //    Note: The delimiter between each numeric value can be any non-numeric character.
  //          The leading dot '.' and square brackets '[]' must be as shown        
  //          HH, MM, and SS must each be 2 valid time-digits    
  //
  QRegExp rx("^.+"                      // NAME
             "\\.\\[([0-9][0-9])[^0-9]" // .[HH.
                   "([0-5][0-9])[^0-9]" //   mm.
                   "([0-5][0-9])\\]"    //   ss]
             "\\.\\[([0-9][0-9])[^0-9]" // .[HH.
                   "([0-5][0-9])[^0-9]" //   mm.
                   "([0-5][0-9])\\]"    //   ss]
             "\\.([^0-9]+)$");          // .EXTN
  //
  QString qstrIni;
  rx.setPatternSyntax(QRegExp::RegExp);
  if(rx.exactMatch(name)) {
      bool ok;
      QString qstrDlm(".");
      QString qstrBegEnd = rx.cap(1) + rx.cap(2) + rx.cap(3)
                         + rx.cap(4) + rx.cap(5) + rx.cap(6);
      hash += qstrBegEnd.toLongLong(&ok,10); // The UNIQUE-FIER
      //
      quint32 quiBegSec=(rx.cap(1).toULong(&ok,10)*3600)
                       +(rx.cap(2).toULong(&ok,10)*  60)
                       +(rx.cap(3).toULong(&ok,10));
      quint32 quiEndSec=(rx.cap(4).toULong(&ok,10)*3600)
                       +(rx.cap(5).toULong(&ok,10)*  60)
                       +(rx.cap(6).toULong(&ok,10));
      quint32 quiDifSec=(quiEndSec-quiBegSec);
      // 
      QString qstrBegIni = "-ss "     + QString::number(quiBegSec);
      QString qstrEndIni = "-endpos " + QString::number(quiDifSec);
              qstrIni    = qstrBegIni + " " + qstrEndIni;
  }
  // fred mod end block
  // =====================================================================
  // fred NOTE: the following 2 lines are a single line in smplayer-0.6.9

    QString hexhash("");
    hexhash.setNum(hash,16);

  // =====================================================================
  // fred mod begin block  
    if( !qstrIni.isEmpty() ) {
      // ** The next code line is not ideal, but should be okay so long 
      //    as SMPlayer's options are set to use Multiple .ini files.  
      //       The literal "file_settings" is HARDCODED, as It wasnt' straight
      //       forward to get the value, The rest of the path was easily available 
      //       without any significant mods, which "file_settings" would require.    
      // TODO: Check for Multiple .ini Option being enabled.
      //  
      QString  dir_settings = Paths::configPath() + "/file_settings";
      QString fqfn_settings = dir_settings + "/" + hexhash[0] + "/" + hexhash + ".ini";

      QSettings set(fqfn_settings, QSettings::IniFormat);
      set.beginGroup("file_settings");
      set.setValue(  "starting_time", "0" );
      set.setValue(  "mplayer_additional_options", qstrIni );
    }
  // fred mod end block
  // =====================================================================

    return hexhash;
}

1

Tôi không thể tìm hiểu xem những thứ này có thực sự có thể được áp dụng cho danh sách phát hay không nhưng bạn có thể xem qua Chỉnh sửa Danh sách Quyết định (EDL). Dưới đây là một số liên kết để giúp bạn bắt đầu:

  1. Hướng dẫn MPlayer về hỗ trợ EDL

  2. Hướng dẫn MPLayer EDL

  3. Chỉnh sửa video từ bài viết dòng lệnh LinuxGazette

  4. Dự án điện ảnh hợp lý

Nếu bạn không bận tâm đến những lần tạm dừng nhỏ giữa các video, bạn có thể chạy trình phát nhiều lần từ một tập lệnh với các tệp EDL khác nhau mỗi lần. Nếu tạm dừng là không có thì có lẽ bạn nên tạo một video mới giống như varrtto đã đề xuất.


Tuy nhiên, cảm ơn, bằng cách sử dụng dòng lệnh, tôi nghĩ rằng sử dụng mplayers -ss và -endpose + macro emacs của tôi là cách tốt hơn để xem (xem phần bổ sung của tôi vào bài viết gốc). Những gì tôi thực sự muốn là một GUI đẹp.
sinh viên
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.